【问题标题】:Redux & React Router: Combing dispatch and navigation (history.push)Redux & React Router:结合调度和导航(history.push)
【发布时间】:2018-06-06 01:44:08
【问题描述】:

对于如何将 React Router 的 history.push('/route')Redux 一起使用,我有点不知所措。

也就是说,如果你用 Redux 的 mapDispatchToProps 连接一个组件,你怎么把应该在 dispatch 某个 action 后触发的 history.push('/route') 放在?

为了澄清这个问题,这是我的实验的 sn-p...

class PostContainer extends React.Component {

    handleSubmit(data) {
        return this.props.addPost(data);
    }

    render() {
        return (<Post onSubmit={data=> this.handleSubmit(data)}/>);
    }
}

const mapDispatchToProps = (dispatch) => {
    return {    
        addPost: (data) => {
            dispatch(addPost(data)).data.then((result) => {
                dispatch(addPostFulfilled(result.data));

                //How do you call the following function?
                this.props.history.push('/posts')
            }).catch((error) => {
                dispatch(addPostRejected());
            });
        },      
    }
}

export default connect(null, mapDispatchToProps)(PostContainer);

如您所见,只要通过addPostFulfilled 将帖子添加到Redux 的状态,页面就需要通过history.push 移动到/posts

根据 Redux 的文档,容器用于更新状态(以及获取数据)。所以,愚蠢的组件不应该放像history.push这样的东西。

有什么比上面的代码更好的方法?

我们将不胜感激。

【问题讨论】:

    标签: javascript redux react-router react-redux


    【解决方案1】:

    您可以使用 react-router-redux(需要初始设置)并从动作创建者处分派您的动作

    import { push } from 'react-router-redux'
    class PostContainer extends React.Component {
    
      handleSubmit(data) {
        return this.props.addPost(data);
      }
    
      render() {
        return (
          <div>
            <Post onSubmit={data=> this.handleSubmit(data)}/>
          </div>
        );
      }
    }
    
    const mapDispatchToProps = (dispatch) => {
      return {    
        addPost: (data) => {
          dispatch(addPost(data)).data.then((result) => {
            dispatch(addPostFulfilled(result.data));
    
            //How do you call the following function?
            dispatch(push('/posts'));
          }).catch((error) => {
            dispatch(addPostRejected());
          });
        },      
      }
    }
    export default connect(null, mapDispatchToProps)(PostContainer);
    

    或者只是将推送作为“完成回调”传递。

    class PostContainer extends React.Component {
    
      handleSubmit(data, done) {
        return this.props.addPost(data, done);
      }
    
      render() {
        const { push } = this.props.history;
        return (
          <div>
            <Post onSubmit={data=> this.handleSubmit(data, push)}/>
          </div>
        );
      }
    }
    
    const mapDispatchToProps = (dispatch) => {
      return {    
        addPost: (data, done) => {
          dispatch(addPost(data)).data.then((result) => {
            dispatch(addPostFulfilled(result.data));
    
            //How do you call the following function?
            done('/posts')
          }).catch((error) => {
            dispatch(addPostRejected());
          });
        },      
      }
    }
    
    export default connect(null, mapDispatchToProps)(PostContainer);
    

    【讨论】:

    • 非常感谢您的建议。那么,在mapDispatchToProps 中包含除 Redux 操作之外的其他内容是否可以接受?你的代码运行得非常好,但是在 mapDispatchToProps 中看到 done('/posts') 仍然让我感到有些尴尬,因为 React Router 的历史本身与 Dispatch 无关(我没有使用 react-router-redux)。我的意思是,mapDispatchToProps 似乎在处理 Redux 的操作,而不是其他任何事情。我是不是想多了?
    【解决方案2】:

    更简洁的方法可能是使用 React Router 的 &lt;Redirect&gt;:

    class PostContainer extends React.Component {
      render() {
        if (userJustAddedAPostRightNow === true) {
          return <Redirect to='/posts' />
        }
        return (
          <div>
            <Post onSubmit={addPost}/>
          </div>
        );
      }
    }
    export default connect(null, { addPost })(PostContainer);
    

    addPost 如果成功,将触发状态更改。它应该将userJustAddedAPostRightNow 更改为 true,以便您将被重定向到帖子页面。

    为避免所有这些嵌套回调,您可以关注 Nir Kaufman's approach 并在中间件中处理逻辑:

    //src/middlewares/post.js
    export const newPost = ({dispatch}) => next => action => {
      next(action);
    
      if (action.type === ADD_POST) {
        dispatch(apiRequest('POST', action.URL, null, ADD_POST_SUCCESS, ADD_POST_ERROR));
        dispatch(showSpinner());
      }
    };
    

    然后,如果成功,ADD_POST_SUCCESS 操作将通过您的 reducer 更改 userJustAddedAPostRightNow 的值。

    【讨论】:

      【解决方案3】:

      恕我直言,您甚至可以从您的愚蠢组件中执行history.push,即

      const mapDispatchToProps = (dispatch) => {
          return {    
              addPost: (data) => {
                  dispatch(addPost(data)).data.then((result) => {
                      dispatch(addPostFulfilled(result.data));
                      <!-- removed from here -->
                  }).catch((error) => {
                      dispatch(addPostRejected());
                  });
              },      
          }
      }
      

      完成addPostFulFilled 数据后,您可以选择在组件本身中执行this.history.push('/route')。您可以使用props 更新时调用的任何生命周期方法来执行此操作。 也许,将其添加到componentWillReceiveProps

      class PostContainer extends React.Component {
        componentWillReceiveProps(nextProps){
        /*Added here*/
        if(nextProps.someFlag){ this.props.history.push('/someRoute');
      }}
      

      请注意,上述方法仅在以下情况下有效

      1. 您可以不通过store跟踪位置变化。(Read More)
      2. 您正在使用react-router-4,在这种情况下,您将使用withRouter 包装您的连接,这将使历史对象作为道具出现在PostContainer 中。
      3. 应注意防止不必要的重新渲染,并在shouldComponentUpdate 中写入必要的逻辑。

      如果上面的内容听起来像是一堆废话,您可以随时使用react-router-reduxpush API,它可以在浏览器历史记录中推送新条目。您可以在您选择的任何地方导入它,然后推送一条新路线。

      详情可在react-router-redux github pages 中查看并引用文档

      push 和 replace 都包含一个位置描述符,它可以是一个 描述 URL 的对象或纯字符串 URL。这些动作创造者 也可以在单个对象中作为 routerActions 使用,它可以是 在使用 Redux 的 bindActionCreators() 时方便使用。

      因此,请直接在 mapDispatchToProps 中使用 history.push(),或者将它们作为道具传递给 PostContainer 反应组件。


      【讨论】:

        【解决方案4】:

        在我的情况下,history.push() 不能直接工作,

        所以我找到了一个替代方法,我们应该通过window.location.reload();重新加载窗口

        它对我有用!

        【讨论】:

        • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
        猜你喜欢
        • 2019-08-24
        • 2018-05-13
        • 2018-10-16
        • 1970-01-01
        • 2020-05-28
        • 2021-02-01
        • 2017-09-28
        • 2016-04-15
        • 2017-10-04
        相关资源
        最近更新 更多