首页 > 解决方案 > 如何使用 react-redux 更改功能组件中的路由器历史记录

问题描述

我正在尝试将代码库从class组件迁移到functional组件,但是当我这样做时,我的历史记录(browserHistory)和重定向停止工作。

我不知道这是我使用的方式useEffect,还是强迫history.push?但我得到了Warning: You cannot change <Router history> 一个RouterConnected Routerstate我从and中获得了正确的值,并且当我只是没有发生这种情况redux时,我可以看到该位置的变化。console.loghistory.push

我正在使用react-reduxconnected-react-router

问题可能是什么?

用例:Facebook API 加载,当用户使用 Facebook 登录时,用户被重定向到另一个页面。

此代码有效:class Component (old code)

class App extends Component {
      constructor(props) {
        super(props);
    
        this.facebookInterval = undefined;
        this.history = createBrowserHistory();
    
        this.state = {
          hasFB: false,
          error: false,
        };
      }
    
      /**
       * Load the Facebook SDK
       *
       * @return {void}
       */
      componentDidMount() {
    
        this.facebookInterval = setInterval(() => {
          if (window.FB !== undefined) {
            this.setState({
              hasFB: true,
            });
    
            clearInterval(this.facebookInterval);
          }
        }, 100);
    
        window.fbAsyncInit = function () {
          window.FB.init({
            appId: process.env.REACT_APP_NEW_MESSENGER_APP_ID,
            autoLogAppEvents: true,
            xfbml: true,
            version: 'v3.3',
          });
        };
    
        (function (d, s, id) {
          var js,
            fjs = d.getElementsByTagName(s)[0];
          if (d.getElementById(id)) {
            return;
          }
          js = d.createElement(s);
          js.id = id;
          js.src =
            'https://connect.facebook.net/en_US/sdk.js?xfbml=1&version=v9.0&appId=' +
            process.env.REACT_APP_NEW_MESSENGER_APP_ID;
          fjs.parentNode.insertBefore(js, fjs);
        })(document, 'script', 'facebook-jssdk');
      }
    
    
      // [NOTE]: This works when using the class component
      // the redirect happens
    
      componentWillUpdate = (nextProps, nextState) => {
        console.log('nextProps.redirect', nextProps.redirect)
        console.log('nextProps', nextProps)
        console.log('nextState', nextState)
    
        if (nextProps.redirect !== undefined && nextProps.redirect !== '/') {
          this.history.push(nextProps.redirect);
        }
      };
    
      render() {
        const { t } = this.props;
    
        if (this.state.hasFB) {
          return (
            <>
              <Elements stripe={stripePromise}>
                <ConnectedRouter history={this.history}>{routes}</ConnectedRouter>
              </Elements>
            </>
          );
        } else {
          return null;
        }
      }
    }
    
    const mapStateToProps = (state) => {
    
      let isLoading = state.siteR.isLoading ? 'open' : 'close';
    
    
      let data = {
        redirect: state.siteR.location,
        isLoading: isLoading,
    
        user: state.userR[state.userR.id],
        id: state.userR.id,
      };
    
      if (state.userR[state.userR.id] !== undefined) {
        data.models = state.userR[state.userR.id].models;
      }
    
      return data;
    };
    
    const mapDispatchToProps = (dispatch) => {
      return {
        // ommited_code
      };
    };
    
    export default compose(
      connect(mapStateToProps, mapDispatchToProps),
      withTranslation(),
    )(App);

相同的代码,但在功能组件上(新代码

  const App = (props) => {
    
      console.log('props', props)
      // console.log('props.redirect', props.redirect)
      
      const [hasFB, setHasFB] = useState(false)
      const [error, setError] = useState(false)
      const [redirect, setRedirect] = useState(props.redirect)
    
    
      const history = createBrowserHistory()
      let facebookInterval = undefined
    
      const {t} = useTranslation()
    
      const initializeFacebook = () => {
        facebookInterval = setInterval(() => {
          if (window.FB !== undefined) {
            setHasFB(true)
            clearInterval(facebookInterval);
          }
        }, 100);
    
        window.fbAsyncInit = function () {
          window.FB.init({
            appId: process.env.REACT_APP_NEW_MESSENGER_APP_ID,
            autoLogAppEvents: true,
            xfbml: true,
            version: 'v3.3',
          });
        };
    
        (function (d, s, id) {
          var js,
            fjs = d.getElementsByTagName(s)[0];
          if (d.getElementById(id)) {
            return;
          }
          js = d.createElement(s);
          js.id = id;
          js.src =
            'https://connect.facebook.net/en_US/sdk.js?xfbml=1&version=v9.0&appId=' +
            process.env.REACT_APP_NEW_MESSENGER_APP_ID;
          fjs.parentNode.insertBefore(js, fjs);
        })(document, 'script', 'facebook-jssdk');
      }
    
    
    // [NOTE]:  I get the right values from props.redirect
    // and  the state
    // the redirect just doesnt happen
    const handleRedirect = () => {
    
      if (props.redirect !== undefined && props.redirect !== '/') {
        console.log('redirect on setRedirect', redirect)
        setRedirect(history.push(props.redirect))
      }
    }
    
      useEffect(() => {
        initializeFacebook()
        handleRedirect()
        console.log('redirect on setRedirect', redirect)
      }, [])
    
    
      if (hasFB) {
        return (
          <>
            <Elements stripe={stripePromise}>
              <ConnectedRouter history={history}>{routes}</ConnectedRouter>
            </Elements>
          </>
        );
      } else {
        return null;
      }
    }
    
    
    const mapStateToProps = (state) => {
    
      let isLoading = state.siteR.isLoading ? 'open' : 'close';
      let showModelSelect = state.modelR.showModelSelect ? 'open' : 'close';
      let showModelAdd = state.modelR.showModelAdd ? 'open' : 'close';
    
      let data = {
        redirect: state.siteR.location,
        isLoading: isLoading,
    
        user: state.userR[state.userR.id],
        id: state.userR.id,
      };
    
      if (state.userR[state.userR.id] !== undefined) {
        data.models = state.userR[state.userR.id].models;
      }
    
      return data;
    };
    
    const mapDispatchToProps = (dispatch) => {
      return {
        // ommited_code
      };
    };
    
    export default compose(
      connect(mapStateToProps, mapDispatchToProps),
      withTranslation(),
    )(App);

我试图切换到/从的路线

const routes =  (
  <div>
    <Switch>
      <SentryRoute exact path='/' component={UserLogin} />

      <SentryRoute exact path='/user' component={Profile} />

        {/* // omited_code */}
    </Switch>
  </div>
)

export default routes;

标签: react-reduxreact-hooksbrowser-historyconnected-react-router

解决方案


从文档中,您似乎可以在connect函数中使用附加参数。

import { push } from 'connected-react-router';

/* code stuffs */
props.push('/home');

export default connect(null, { push })(Component);

https://github.com/supasate/connected-react-router/blob/master/FAQ.md#with-react-redux


推荐阅读