React页面刷新时State是否变化?主题切换后跳转复原问题咨询
问题解答:React State刷新变化与主题持久化问题
咱们先一个个来解决你的问题哈:
一、刷新页面时React的State会发生变化吗?
那肯定会啊!React组件的State是存在内存里的临时状态,一旦你刷新页面,整个应用会重新加载,所有组件都会从头初始化,State直接回到你在constructor里设置的初始值,之前的状态直接就没了。这也是为啥你切换主题后刷新,主题会变回初始状态的核心原因之一。
二、主题切换后跳转页面恢复初始状态的问题分析与解决
看了你的App组件代码,主题状态isPrim存在App的State里,但有两个关键问题:
- 状态只存内存,没做持久化,刷新就丢;
- 只有AboutPage和ResumePage接收了
isPrim属性,其他页面比如Home、Portfolio这些根本没拿到主题状态,自然显示初始样式。
一步步解决:
1. 把主题状态持久化到localStorage
咱们把主题状态存在浏览器的localStorage里,这样就算刷新页面、重新打开浏览器,都能读取之前保存的主题偏好。修改你的App组件:
- 初始化State时,先从localStorage读,没有的话用默认值
true; - 切换主题时,更新State的同时把新状态存到localStorage。
修改后的代码:
class App extends React.Component { constructor() { super(); this.sideBarToggleHandler = this.sideBarToggleHandler.bind(this); // 先从localStorage取保存的主题,没有就用默认值 const savedTheme = localStorage.getItem('isPrim'); this.state = { sideBarOpen: true, backDropOpen: false, isPrim: savedTheme !== null ? JSON.parse(savedTheme) : true, } } sideBarToggleHandler = () => { this.setState((prevState) => ({ sideBarOpen: !prevState.sideBarOpen })); this.setState((prevState) => ({ backDropOpen: !prevState.backDropOpen })); } changeTheme = () => { this.setState((prevState) => { const newTheme = !prevState.isPrim; // 把新主题存到localStorage localStorage.setItem('isPrim', JSON.stringify(newTheme)); return { isPrim: newTheme }; }); } render() { let backDrop; if (this.state.backDropOpen) { backDrop = <SideDrop />; } return ( <div className="App"> <SimpleBar style={{ height: '100vh' }}> <ThemeSwitcher changeTheme={this.changeTheme} /> <ToggleBar sideBarToggleHandler={this.sideBarToggleHandler} /> {backDrop} <SideBar sideBarOpen={this.state.sideBarOpen} /> <Switch> {/* 所有页面都用render方法传递isPrim属性 */} <Route exact path='/' render={() => <HomePage isPrim={this.state.isPrim} />} /> <Route exact path='/about' render={() => <AboutPage isPrim={this.state.isPrim} />} /> <Route exact path='/resume' render={() => <ResumePage isPrim={this.state.isPrim} />} /> <Route exact path='/portfolio' render={() => <PortfolioPage isPrim={this.state.isPrim} />} /> <Route exact path='/blog' render={() => <BlogPage isPrim={this.state.isPrim} />} /> <Route exact path='/contact' render={() => <ContactPage isPrim={this.state.isPrim} />} /> </Switch> </SimpleBar> </div> ); } }
2. 确保所有页面组件都用这个主题状态
接下来要在每个页面组件里,根据接收到的isPrim属性来切换对应的CSS类或者样式,比如:
// 举个HomePage的例子 class HomePage extends React.Component { render() { const themeClass = this.props.isPrim ? 'primary-theme' : 'secondary-theme'; return ( <div className={`home-page ${themeClass}`}> {/* 页面内容 */} </div> ); } }
3. 进阶:用React Context简化全局状态传递
如果你的应用组件层级比较深,或者很多组件都需要用到主题状态,每次通过props一层层传递太麻烦,这时候可以用React Context来做全局状态管理,不用再手动传props了。
简单实现一下:
// 先创建一个ThemeContext const ThemeContext = React.createContext(); // 写一个ThemeProvider组件,封装主题状态和切换方法 class ThemeProvider extends React.Component { constructor(props) { super(props); const savedTheme = localStorage.getItem('isPrim'); this.state = { isPrim: savedTheme !== null ? JSON.parse(savedTheme) : true, changeTheme: () => { this.setState(prevState => { const newTheme = !prevState.isPrim; localStorage.setItem('isPrim', JSON.stringify(newTheme)); return { isPrim: newTheme }; }); } }; } render() { return ( <ThemeContext.Provider value={this.state}> {this.props.children} </ThemeContext.Provider> ); } } // 然后在根组件里包裹App ReactDOM.render( <ThemeProvider> <App /> </ThemeProvider>, document.getElementById('root') ); // 现在在ThemeSwitcher里直接用Context,不用传changeTheme props了 class ThemeSwitcher extends React.Component { static contextType = ThemeContext; render() { return ( <button onClick={this.context.changeTheme}> 切换主题 {this.context.isPrim ? '到深色' : '到浅色'} </button> ); } } // 页面组件也可以直接取主题状态,不用接props了 class HomePage extends React.Component { static contextType = ThemeContext; render() { const themeClass = this.context.isPrim ? 'primary-theme' : 'secondary-theme'; return ( <div className={`home-page ${themeClass}`}> 首页内容 </div> ); } }
这样不管组件层级多深,都能直接获取主题状态和切换方法,维护起来方便很多~
内容的提问来源于stack exchange,提问作者Hafed
相关产品推荐
相关产品推荐

