使用react-router切换路由时React组件state被重置,是什么原因?
问题核心原因
你之前查询的资料对应的是路由持续匹配时的组件重渲染场景,和你现在遇到的路由切换场景完全不同:
component/render写法的区别:仅当路由一直处于匹配状态时,component={Comp}写法会因为父组件重渲染时持续生成新的组件实例,导致state意外重置,改用render={() => <Comp />}可以避免该问题,但这一规则仅适用于组件不被卸载的前提。- 你当前遇到的问题本质:使用
Switch组件时,同一时间仅会渲染路径匹配的唯一路由组件,当你从/state切换到/dummy时,StateComp会被直接卸载,内部的counterstate自然会被销毁,切回/state时组件重新挂载,state会被初始化为0,和你用哪种路由渲染写法无关。
可行解决方案
方案1:状态提升(最推荐,无额外依赖)
将需要持久化的state提到不会被路由切换卸载的上层组件(比如App/RoutesComp),通过props/context传递给StateComp:
// App.js 改造示例 import RoutesComp from "./RoutesComp"; import { Link } from "react-router-dom"; import { useState } from "react"; function App() { // 把counter state提到App层,App不会被路由切换卸载 const [counter, setCounter] = useState(0); return ( <div className="App"> <p> <Link to="/state">State</Link> </p> <p> <Link to="/dummy">dummy</Link> </p> <RoutesComp counter={counter} setCounter={setCounter} /> </div> ); } export default App;
// RoutesComp.js 改造示例 import React from "react"; import { Route, Switch } from "react-router-dom"; import StateComp from "./StateComp"; import Dummy from "./Dummy"; const RoutesComp = (props) => { return ( <Switch> <Route path="/state" render={() => <StateComp counter={props.counter} setCounter={props.setCounter} />} /> <Route path="/dummy" render={() => <Dummy />} /> </Switch> ); }; export default RoutesComp;
// StateComp.js 改造示例 import React from "react"; const StateComp = ({counter, setCounter}) => { return ( <> <button onClick={() => setCounter(prev => prev + 1)}>点击计数</button> <p>{counter}</p> </> ); }; export default StateComp
方案2:组件持久化缓存
使用路由缓存库包裹需要保活的路由组件,切换路由时组件仅隐藏不卸载,切回时直接恢复原有状态,适合复杂页面不想抽离状态的场景。
方案3:本地持久化存储
将counter值同步存储到localStorage/sessionStorage,StateComp挂载时从存储中读取初始值,更新时同步写入存储,就算组件重新挂载也能恢复之前的数值,适合刷新页面也需要保留状态的场景。
方案4:修改路由渲染逻辑
去掉Switch组件,同时渲染所有路由,给不匹配路径的路由添加display: none隐藏,仅展示匹配路径的路由,该方案实现简单但路由多了会有性能损耗,不推荐复杂项目使用。
内容的提问来源于stack exchange,提问作者Jac Frall
相关产品推荐
相关产品推荐

