Redux & React Router:结合调度和导航(history.push)
Posted
技术标签:
【中文标题】Redux & React Router:结合调度和导航(history.push)【英文标题】:Redux & React Router: Combing dispatch and navigation (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
这样的东西。
有什么比上面的代码更好的方法?
我们将不胜感激。
【问题讨论】:
【参考方案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 的 <Redirect>
:
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');
请注意,上述方法仅在以下情况下有效
-
您可以不通过
store
跟踪位置变化。(Read More)
您正在使用react-router-4
,在这种情况下,您将使用withRouter
包装您的连接,这将使历史对象作为道具出现在PostContainer
中。
应注意防止不必要的重新渲染,并在shouldComponentUpdate
中写入必要的逻辑。
如果上面的内容听起来像是一堆废话,您可以随时使用react-router-redux
的push
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。以上是关于Redux & React Router:结合调度和导航(history.push)的主要内容,如果未能解决你的问题,请参考以下文章
菜鸟webpack/react/redux/react-router/ts一步步搭建架子
使用 React-Router 和 Redux 时单击链接时如何调度操作?
路由/重定向不在 React Router 4 和 Redux 授权中呈现
React-Router-Redux:在“react-router-redux”中找不到导出“syncHistoryWithStore”