react-router 5搭配Redux7使用Link跳转新路由时状态未重置如何解决
问题根因
你的问题核心原因有两个:
- 相同路由规则匹配同一个组件时,React不会卸载重建组件,仅会触发组件更新,你当前只在
componentDidMount中触发数据请求,参数变更后不会重新拉取数据 - Redux中持久存储了上一次访问的公司数据,新数据请求完成前旧数据会被渲染,导致出现短暂的旧内容闪现
你的依赖配置完全适配react-router v5,不需要调整版本或基础配置。
方案1:给Route添加key属性(最便捷)
在路由配置中给匹配的Route添加和companyId绑定的key,当参数变化时React会强制卸载旧组件挂载新组件,自动触发componentDidMount重新拉取数据,无需修改组件逻辑:
// 修改App.tsx中的路由配置 <Route component={withTracker(InterviewContainer)} path="/interviews/companies/:companyId" key={(route) => route.match.params.companyId} />
方案2:新增组件生命周期监听参数变化
在InterviewContainer中新增componentDidUpdate生命周期,检测路由参数变化时先清空旧数据再拉取新数据,同时可以在组件卸载时清空数据避免全局残留:
- 先在Redux的company模块新增
resetCompanyaction,用来将store中的company值重置为undefined - 修改
InterviewContainer代码:
class InterviewContainer extends Component<PropsFromRedux & RouteComponentProps<{ companyId: string }>> { componentDidMount() { const { fetchCompany } = this.props; const { companyId } = this.props.match.params; fetchCompany(companyId); } componentDidUpdate(prevProps) { const prevCompanyId = prevProps.match.params.companyId; const currentCompanyId = this.props.match.params.companyId; if (prevCompanyId !== currentCompanyId) { // 先清空旧数据,避免闪现旧内容 this.props.resetCompany(); // 拉取新公司数据 this.props.fetchCompany(currentCompanyId); } } componentWillUnmount() { // 离开页面时清空全局残留的公司数据 this.props.resetCompany(); } render() { const { company } = this.props; return (company && <Interview className="ft-interview" company={company} />) || null; } } // 记得把resetCompany加入mapDispatch const mapDispatch = { fetchCompany: fetchCompanyFromJSON, resetCompany: resetCompanyAction };
方案3:全局监听路由变化重置状态
不需要依赖第三方库,直接抽离全局history对象监听路由变化即可:
- 单独创建
history.ts文件抽离路由实例:
import { createBrowserHistory } from 'history'; export default createBrowserHistory();
- 修改
index.tsx中的Router配置,使用自定义history:
import { Router } from 'react-router-dom'; import history from './history'; render( <> <div className="Site"> <Provider store={store}> <Router history={history}> <App /> </Router> </Provider> </div> <Footer /> </>, );
- 在store初始化的位置监听路由变化,符合条件时触发清空action:
import history from './history'; history.listen((location) => { // 离开面试详情页时清空公司数据 if (!location.pathname.startsWith('/interviews/companies/')) { store.dispatch(resetCompanyAction()); } });
内容的提问来源于stack exchange,提问作者PositiveGuy
相关产品推荐
相关产品推荐

