在路由转换时触发 Redux 操作
介绍
路由是任何复杂的 React Web 应用程序中的关键组件,而react-router是 React 最常用的路由库。虽然它在简单的路由任务中表现完美,但在处理复杂情况时,解决方案并不简单。
例如,在博客应用程序中,您可能希望创建用于查看博客文章列表和查看单个博客文章的路由。显而易见的设计如下:
- PostList组件将从 API 加载当前博客文章集并将其显示在列表中。这些文章存储在应用程序状态中。
- 用户从列表中选择一个帖子。
- 将选择的帖子对象分配给activePost变量。
- 执行到Post组件的路由转换,该组件主要显示来自activePost变量的内容。
如果用户总是从PostList组件开始导航,这种方法效果很好。但更强大的应用程序会允许用户直接输入特定 URL,并期望应用程序显示相应的帖子。例如,用户输入https://myapp.com/posts/awesome-post,应用程序会导航到Post组件并显示 awesome-post 文章的内容。由于此实例中未设置activePost变量,因此视图最终将为空。
在本指南中,我们将探索这些用例的解决方案。为了概括本指南的范围,我们将重点介绍在路由转换时触发任何 Redux 操作,而不是 API 调用。
使用组件生命周期
一种解决方案是在组件生命周期中处理操作。此解决方案适用于在路由转换时触发的操作仅影响当前组件的情况。在类组件中,我们可以结合使用componentDidMount和componentWillReceiveProps事件来达到所需的效果。
让我们假设一个 Redux 存储,配置如下,以及在路由转换时需要触发的操作。
// reducer.js
import { ACTION_TO_FIRE } from './actions.js'
const initialState = {
// ...
}
export default function appReducer(state, action) {
if (typeof state === 'undefined') {
return initialState
}
switch(action.type){
case ACTION_TO_FIRE:
// do something with the payload
break;
}
// actions.js
// These are our action types
export const ACTION_TO_FIRE = "ACTION_TO_FIRE"
// Now we define actions
export function fireThisAction(payload){
return {
type: ACTION_TO_FIRE,
payload
}
}
有了这个,我们的类组件就会在路线转换时触发fireThisAction 。
// AppComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { withRouter } from 'react-router'
import { fireThisAction } from './actions';
class AppComponent extends Component {
componentDidMount(){
fireThisAction();
}
componentWillReceiveProps (nextProps) {
if (this.props.location.pathname === nextProps.location.pathname &&
this.props.location.search === nextProps.location.search
) {
// this means that no change in the path, so we don't need to refire the
// action
return;
}
// if not fire the action
fireThisAction();
}
render(){
return (
// render the content here after loading data
);
}
}
function mapStateToProps(state) {
return {
}
}
const mapDispatchToProps = {
fireThisAction
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(AppComponent));
如上面的代码示例所示,我们首先使用componentDidMount在路由转换时加载数据。但为了使其适用于所有已安装组件的情况(例如:在不卸载组件的情况下更改路由),我们需要重写 componentWillReceiveProps事件并查看是否需要重新触发该操作。我们只是比较当前 URL 的完整路径来确定是否重新触发该操作。
在实际应用中,您会发现只需要比较某个路径参数即可确定这一点。如果我们考虑上面的博客文章示例,我们需要检查指示帖子 slug(“awesome-post”)的路径参数是否已更改。这可以通过比较props.match.params的内容轻松完成。
使用事件监听器
另一种用例是,每次发生路由转换时,您都需要触发 Redux 操作。例如,每次用户导航到一组页面时,应用可能需要调用日志 API。我们可以使用全局事件监听器来完成任务,而不是在每个页面组件中指定日志调用(如上一个用例所示)。监听器将绑定到路由器历史记录。
为了清楚起见,我们假设 Redux 存储和路由器历史记录在相应的文件中可用,如下所示。
注意:本指南针对的是 react-router-v4,即正在使用的最新版本。对于以前的 react-router 版本,这可能会略有不同。在这些情况下,必须将history替换为browserHistory或hashHistory,具体取决于应用程序中的使用情况。
// history.js
import createHistory from 'history/createBrowserHistory';
// this history object is used for the history parameter in our Router
// <Router history={history}> ... </Router>
const history = createHistory();
export default history;
// store.js
import { createStore } from 'redux'
import { appReducer } from './reducer.js'
const store = createStore(appReducer)
export default store;
现在我们在history.js内部实现事件监听器。每次发生路由器转换时,都会以当前位置对象作为参数调用该监听器。
// history.js
import createHistory from 'history/createBrowserHistory';
import store from './store.js'
import { fireThisAction } from './actions';
const history = createHistory();
history.listen((location) => {
store.dispatch(fireThisAction(location));
})
export default history;
在fireThisAction中,可以执行条件任务。必须注意的是,您可以调用侦听器中的任何函数。
结论
在任何实际应用中,路由转换都是不可避免的。转换通常是对用户操作的响应。在其他情况下,它可能是由用户或应用本身的 URL 更改触发的。在本指南中,我们探讨了两种从应用组件跟踪路由更改的方法。每种方法都有自己的用例,必须相应地使用。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~