React Router切换路由时如何防止组件状态值被重置
问题根本原因
你遇到的重置问题是React Router默认路由匹配逻辑导致的:当路由跳转到/时,/setting对应的Route不匹配,<Setting>组件会直接被卸载,所有内部state都会被清空;再次切回/setting时组件重新挂载,useState就会重新初始化默认值6。
下面是3种可直接落地的解决方案:
方案1:路由组件缓存渲染(改码量最少)
通过children形式的Route渲染,用CSS控制显示隐藏,不会卸载组件,不需要修改Setting组件的任何代码:
// 修改index.js中的路由部分代码 export default class BasicExample extends Component { render() { return ( <Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/setting">Setting</Link> </li> </ul> <hr /> <Route exact path="/" component={Home} /> {/* 核心修改:用children回调+css控制显隐,组件不会卸载 */} <Route path="/setting" children={({match}) => ( <div style={{display: match ? 'block' : 'none'}}> <Setting /> </div> )} /> </div> </Router> ); } }
方案2:状态提升到父组件管理
把val状态放到上层的BasicExample组件中,通过props传递给Setting,就算Setting卸载,状态保存在父组件不会丢失:
- 修改index.js:
export default class BasicExample extends Component { // 把Setting的状态提到父组件存储 state = { settingVal: 6 } setSettingVal = (val) => { this.setState({settingVal: val}) } render() { return ( <Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/setting">Setting</Link> </li> </ul> <hr /> <Route exact path="/" component={Home} /> <Route path="/setting"> {/* 通过props传递状态和修改方法 */} <Setting val={this.state.settingVal} setVal={this.setSettingVal}/> </Route> </div> </Router> ); } }
- 修改Setting.js:
import React from "react"; function Setting(props) { const onlyNumbers = (e) => { const re = /^[0-9\b]+$/; if (e.target.value === "" || re.test(e.target.value)) { props.setVal(parseInt(e.currentTarget.value)); } }; return ( <div> <label>Test</label> <input className="maxcards" value={props.val} onChange={onlyNumbers} /> </div> ); } export default Setting;
该方案适合状态需要在多个页面共享的场景。
方案3:本地存储持久化状态
把修改后的值存在localStorage中,组件挂载时优先从本地取值,就算刷新页面值也不会丢失,只需要修改Setting.js:
import React, { useState, useEffect } from "react"; function Setting(props) { // 初始化优先读本地存储的数值 const [val, setVal] = useState(() => { const savedVal = localStorage.getItem('setting_input_val'); return savedVal ? parseInt(savedVal) : 6; }); // 数值变化自动同步到本地存储 useEffect(() => { localStorage.setItem('setting_input_val', val); }, [val]) const onlyNumbers = (e) => { const re = /^[0-9\b]+$/; if (e.target.value === "" || re.test(e.target.value)) { setVal(parseInt(e.currentTarget.value)); } }; return ( <div> <label>Test</label> <input className="maxcards" value={val} onChange={onlyNumbers} /> </div> ); } export default Setting;
该方案适合需要长期保存的配置类参数。
内容的提问来源于stack exchange,提问作者yongchang
相关产品推荐
相关产品推荐

