React Router切换路由时组件重复挂载丢失状态如何解决?
问题原因与解决方案
问题根因
你当前的写法会触发React Router切换路由时卸载不匹配的路由组件:
- 默认情况下React Router的路由规则是:仅渲染路径匹配的
<Route>下的内容,路径不匹配的内容会直接从DOM树移除,对应组件自然会触发卸载逻辑,内部状态全部丢失。 - 你排查时看到的日志现象符合这个逻辑:App组件未在路由切换时重渲染,所以
renderForm函数只会在App挂载时执行一次输出日志;但路由切走时ActivityForm被卸载,切回时React会根据之前renderForm返回的JSX创建全新的组件实例,所以构造函数会重复执行。
解决方案
方案1:切换路由时保留所有组件状态(推荐)
如果需要切换路由时两个组件的状态都不丢失,改为「全量渲染两个组件、用CSS控制显隐」的实现方案即可,步骤如下:
- 给App组件包裹
withRouter高阶组件,让App可以获取当前路由路径:
import { BrowserRouter as Router, withRouter } from 'react-router-dom'; // 导出组件的时候用withRouter包裹 export default withRouter(App);
- 修改App的render函数,删除原有
<Route>的条件渲染逻辑,改为根据当前路径控制两个组件的显隐:
return ( <div className="container"> <h1 className="text-center main-title">Activity Logger</h1> <Router> <NavigationBar /> {/* 匹配首页时显示表单,否则隐藏 */} <div style={{display: this.props.location.pathname === '/' ? 'block' : 'none'}}> {this.renderForm()} </div> {/* 匹配列表页时显示表格,否则隐藏 */} <div style={{display: this.props.location.pathname === '/activitydisplay' ? 'block' : 'none'}}> {this.renderTable()} </div> </Router> </div> );
如果你的项目用了Bootstrap类名,也可以直接用d-block/d-none类控制显隐,不用写内联样式。
方案2:仅修复不必要的重复挂载
如果你不需要保留切走页面的状态,只需要相同路径进入时不重复挂载组件,只需修改原有<Route>的写法,使用render属性传入渲染函数即可:
<Route exact path="/" render={() => this.renderForm()} /> <Route path="/activitydisplay" render={() => this.renderTable()} />
内容的提问来源于stack exchange,提问作者Sinu Sen
相关产品推荐
相关产品推荐

