React(v18.2.0)应用点击浏览器返回按钮页面不刷新的问题求助
问题:React Router v5点击浏览器返回按钮URL变化但页面不更新
我有一个基于React(v18.2.0)和react-router-dom(v5.2.0)的应用,导航功能正常,但点击浏览器返回按钮时,URL发生变化,但页面状态未更新、也未重新渲染。例如,从ListUserComponent跳转到CreateUserComponent后,点击返回按钮,URL变回列表页路径,但页面仍停留在创建用户页面。
App.js
import React from 'react'; import './App.css'; import {BrowserRouter as Router, Route, Switch} from 'react-router-dom'; import ListUserComponent from './components/ListUserComponent'; import HeaderComponent from './components/HeaderComponent'; import FooterComponent from './components/FooterComponent'; import CreateUserComponent from './components/CreateUserComponent'; import UpdateUserComponent from './components/UpdateUserComponent'; import ViewUserComponent from './components/ViewUserComponent'; function App() { return ( <div> <Router forceRefresh={true}> <HeaderComponent /> <div className="container"> <Switch> <Route path = "/" exact component = {ListUserComponent}></Route> <Route path = "/users" component = {ListUserComponent}></Route> <Route path = "/add-user/:id" component = {CreateUserComponent}></Route> <Route path = "/view-user/:id" component = {ViewUserComponent}></Route> </Switch> </div> <FooterComponent /> </Router> </div> ); } export default App;
CreateUserComponent.jsx
import React, { Component } from 'react'; import UserService from '../services/UserService'; class CreateUserComponent extends Component { constructor(props) { super(props) this.state = { //Step 2 id: this.props.match.params.id, firstName: '', lastName: '', email: '', password: '' } this.changeFirstNameHandler = this.changeFirstNameHandler.bind(this); this.changeLastNameHandler = this.changeLastNameHandler.bind(this); this.saveOrUpdateUser = this.saveOrUpdateUser.bind(this); } //Step 3 componentDidMount() { //Step 4 if (this.state.id === 'add') { return } else { UserService.getUserById(this.state.id).then((res) => { let user = res.data; this.setState({ firstName: user.firstName, lastName: user.lastName, emailId: user.emailId }); }); } } saveOrUpdateUser = (e) => { e.preventDefault(); let user = { firstName: this.state.firstName, lastName: this.state.lastName, email: this.state.email, password: this.state.password }; console.log('user => ' + JSON.stringify(user)); //Step 5 if (this.state.id === 'add') { UserService.createUser(user).then(res => { this.props.history.push('/users'); }); } else { UserService.updateUser(user, this.state.id).then(res => { this.props.history.push('/users'); }); } } changeFirstNameHandler = (event) => { this.setState({ firstName: event.target.value }); } changeLastNameHandler = (event) => { this.setState({ lastName: event.target.value }); } changeEmailHandler = (event) => { this.setState({ email: event.target.value }); } changePasswordHandler = (event) => { this.setState({ password: event.target.value }); } cancel() { this.props.history.push('/users'); } getTitle() { if (this.state.id === 'add') { return <h3 className="text-center">Modificar Usuario</h3> } else { return <h3 className="text-center">Añadir Usuario</h3> } } render() { return ( <div> <div className="container"> <div className="row"> <div className="card col-md-6 offset-md-3 offset-md-3"> { this.getTitle() } <div className="card-body"> <form> <div className="form-group"> <label>Nombre: </label> <input placeholder="Nombre" name="firstName" className="form-control" value={this.state.firstName} onChange={this.changeFirstNameHandler} /> </div> <div className="form-group"> <label> Apellidos: </label> <input placeholder="Apellidos" name="lastName" className="form-control" value={this.state.lastName} onChange={this.changeLastNameHandler} /> </div> <div className="form-group"> <label> Email: </label> <input placeholder="Email" name="email" className="form-control" value={this.state.email} onChange={this.changeEmailHandler} /> </div> <div className="form-group"> <label> Contraseña: </label> <input placeholder="Contraseña" name="password" className="form-control" value={this.state.password} onChange={this.changePasswordHandler} /> </div> <button className="btn btn-success" onClick={this.saveOrUpdateUser}>Guardar</button> <button className="btn btn-danger" onClick={this.cancel.bind(this)} style={{ marginLeft: "10px" }}>Cancelar</button> </form> </div> </div> </div> </div> </div> ) } } export default CreateUserComponent;
package.json
{ "name": "frontend", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.1.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^5.2.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
解决方案
1. 移除forceRefresh={true}
Router组件中的forceRefresh={true}会强制页面整页刷新,在React 18与React Router v5的组合下易导致路由状态异常,直接移除该属性:
<Router> {/* 其余代码保持不变 */} </Router>
2. 给类组件添加路由变化监听
对于ListUserComponent这类类组件,需要监听路由location变化来触发数据重新获取和组件重渲染。通过withRouter高阶组件包裹组件,并使用componentDidUpdate生命周期:
import { withRouter } from 'react-router-dom'; import UserService from '../services/UserService'; class ListUserComponent extends Component { componentDidMount() { this.fetchUsers(); } componentDidUpdate(prevProps) { // 路由location变化时重新拉取数据 if (this.props.location !== prevProps.location) { this.fetchUsers(); } } fetchUsers = () => { UserService.getUsers().then(res => { this.setState({ users: res.data }); }); } // 其余组件代码... } // 用withRouter包裹以获取location属性 export default withRouter(ListUserComponent);
3. 升级react-router-dom到v5最新版本
React 18与react-router-dom v5.2.0存在兼容性隐患,升级到v5系列最新版本可解决部分异常:
npm install react-router-dom@5.3.4
4. 全局监听路由变化(可选)
若上述方法无效,可在App组件中添加全局路由监听,确保页面状态同步:
import { useEffect } from 'react'; import { useHistory } from 'react-router-dom'; function App() { const history = useHistory(); useEffect(() => { const unlisten = history.listen(() => { // 路由变化时可执行全局状态更新逻辑,比如强制刷新列表 }); return () => unlisten(); }, [history]); // 其余组件代码... }
内容的提问来源于stack exchange,提问作者Tempname52
相关产品推荐
相关产品推荐

