React应用导航返回后刷新丢失Redux状态,请求技术支援
React礼品店应用状态丢失问题
问题现象
用户登录后主页正常显示Welcome {username},但进入产品详情页后点击浏览器返回按钮回到主页时,应用触发整页刷新,导致Redux中存储的用户状态全部丢失,需重新登录。
相关代码
App.js
import './App.css'; import Main from './components/main/main'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import { Provider } from 'react-redux'; import store from './store'; import Items from './components/items/items'; import ProductInfo from './components/productInfo/productInfo'; import UserInterface from './components/userInterface/userInterface'; import Profile from './components/profile/profile'; function App() { return ( <Provider store={store}> <Router className="App"> <Routes> <Route exact path='/' element={ <div id='Homepage'> <Profile /> <Main /> <Items/> </div> }></Route> <Route exact path='/product-info/:id' element={<ProductInfo/>}></Route> <Route exact path='/user-form' element={<UserInterface/>}></Route> </Routes> </Router> </Provider> ); } export default App;
Profile.js(负责接收和展示用户数据)
import React, { Component } from 'react' import './profile.css'; import { connect } from 'react-redux'; import { checkUser } from '../../actions/userActions'; class Profile extends Component { state = { user : { isLoggedIn : false, userName : '', email : '', password : '' } } componentDidMount(){ this.props.checkUser() const currentUser = this.props.user.user; console.log(currentUser); this.setState({ user : currentUser }) } render() { const {user} = this.state; return ( <div> {user?.isLoggedIn ? <h2 id='welcome-user'>Welcome {user.userName}</h2> : <a id="profile-area" href='/user-form'> <img src="user.png" alt="profile" id="profile-img" /> </a> } </div> ) } } const mapUserStateToProps = (state) => { return{ user : state?.myUser } } export default connect(mapUserStateToProps, {checkUser})(Profile);
UserInterface.js(登录表单,将输入提交至Redux状态)
import React from 'react' import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router'; import { getUser } from '../../actions/userActions'; import { connect } from 'react-redux'; import './userInterface.css'; function UserInterface(props) { const [userInfo, setUserInfo] = useState({ isLoggedIn : false, userName : '', email : '', password : '' }) const navigate = useNavigate(); let alertMsg = ''; const getInputToState = (e,inputField) => { switch(inputField){ case 'username' : { setUserInfo(userInfo.userName = e.target.value); const newUserInfo = userInfo; setUserInfo(newUserInfo); console.log(userInfo); break } case 'email' : { setUserInfo(userInfo.email = e.target.value); const newUserInfo = userInfo; setUserInfo(newUserInfo); console.log(userInfo); break } case 'password' : { setUserInfo(userInfo.password = e.target.value) ; const newUserInfo = userInfo; setUserInfo(newUserInfo); console.log(userInfo); break } default: return null } } const onSubmit = (e) => { e.preventDefault(); let namePattern = /[A-Za-z0-9]{3,16}./ ; let emailPattern = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/ ; if(userInfo.userName?.match(namePattern) && userInfo.email?.match(emailPattern) && userInfo.password.length >= 8){ setUserInfo(userInfo.isLoggedIn = true); props.getUser(userInfo); navigate("/"); }else{ document.querySelector('#alert-msg').innerText = 'username, email or password are invalid'; } } return ( <div id='user-div'> <form id='user-form'> <h2 id="form-title">Tell us who you are :)</h2> <ul id="form-inputs"> <li className="form-input"> <input type="text" className="user-input" placeholder='Enter a username' maxLength={16} onChange={(e) => getInputToState(e, "username")}/> </li> <li className="form-input"> <input type="text" className="user-input" placeholder='Enter your e-mail' onChange={(e) => getInputToState(e, "email")}/> </li> <li className="form-input"> <input type="text" className="user-input" placeholder='Create a password' onChange={(e) => getInputToState(e, "password")}/> </li> <li className="form-input"> <a><button className='action-form' id='submit-button' onClick={onSubmit}>Submit</button></a> </li> </ul> <h4 id='alert-msg' ></h4> <h3 id='login-sign'>Already have an account ? <a href="/" id='login-form'>Log In</a></h3> </form> </div> ) } const mapStateToProps = (state) => { return { myUser : state?.usersReducer } } export default connect(mapStateToProps, {getUser})(UserInterface) ;
UserReducer.js
const initialState = { user : { isLoggedIn : false, userName : '', email : '', password : '' } }; export default function(state = initialState, action){ switch(action.type){ case 'GET_USER': initialState.user = action.payload; case 'CHECK_USER': return{ ...state } default: return state } }
问题分析与修复方案
核心问题点
- 原生
<a>标签触发整页刷新:Profile和UserInterface组件中使用原生<a href>跳转,会强制浏览器刷新页面,清空内存中的Redux状态。 - Reducer违反不可变更新原则:直接修改
initialState且缺少break语句,导致状态更新不被Redux正确检测。 - Profile组件未同步Redux状态变化:仅在挂载时获取一次状态,后续Redux状态更新无法同步到组件视图。
修复步骤
1. 替换原生跳转为React Router客户端导航
将所有原生<a>标签替换为React Router的Link组件,避免整页刷新:
- Profile.js:导入
Link并替换跳转标签
import { Link } from 'react-router-dom'; // 替换render中的a标签 {user?.isLoggedIn ? <h2 id='welcome-user'>Welcome {user.userName}</h2> : <Link id="profile-area" to='/user-form'> <img src="user.png" alt="profile" id="profile-img" /> </Link> }
- UserInterface.js:同样替换登录跳转的a标签
import { Link } from 'react-router-dom'; // 替换对应代码 <h3 id='login-sign'>Already have an account ? <Link to="/" id='login-form'>Log In</Link></h3>
2. 修复Reducer的状态更新逻辑
遵循Redux不可变原则,正确返回新状态并添加break:
const initialState = { user: { isLoggedIn: false, userName: '', email: '', password: '' } }; export default function(state = initialState, action) { switch(action.type) { case 'GET_USER': return { ...state, user: action.payload }; case 'CHECK_USER': return { ...state }; default: return state; } }
3. 让Profile组件实时同步Redux状态
移除组件自身的user状态,直接使用Redux映射的props,确保视图随状态更新:
import React, { Component } from 'react' import './profile.css'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; import { checkUser } from '../../actions/userActions'; class Profile extends Component { componentDidMount() { this.props.checkUser(); } render() { const { user } = this.props.user; return ( <div> {user?.isLoggedIn ? <h2 id='welcome-user'>Welcome {user.userName}</h2> : <Link id="profile-area" to='/user-form'> <img src="user.png" alt="profile" id="profile-img" /> </Link> } </div> ) } } const mapUserStateToProps = (state) => { return { user: state?.myUser } } export default connect(mapUserStateToProps, { checkUser })(Profile);
4. 可选:持久化Redux状态(防止意外刷新丢失)
若希望页面刷新后仍保留用户状态,可使用redux-persist将状态存储到localStorage:
- 安装依赖:
npm install redux-persist - 修改store配置,添加持久化逻辑
- 在App.js中用
PersistGate包裹路由组件
内容的提问来源于stack exchange,提问作者islam gueniari
相关产品推荐
相关产品推荐

