React路由跳转后组件不刷新 useEffect未触发问题
问题根因
CrudDemo组件中拉取列表数据的useEffect依赖数组为空,仅会在组件首次挂载时执行一次。React Router导航到当前已挂载的同路径组件时,默认会复用已有组件实例,不会触发组件卸载重挂载,因此删除完成后跳转回/CrudDemo路径时,组件不会重新执行useEffect拉取最新数据,页面就会一直展示删除前的旧数据。
解决方案
方案1:抽离数据拉取逻辑,删除成功后主动触发重拉(推荐,体验最优)
不需要做无意义的同路径跳转,删除成功后直接触发列表数据刷新,没有多余路由动作,页面响应更快。
- 修改
CrudDemo组件,抽离独立的数据拉取函数,逐层传递给操作按钮组件:
function CrudDemo(props) { const navigate=useNavigate(); // 所有useState统一放到组件顶部,符合Hooks调用规范 const [PersonList, setPersonList] = useState(); // 抽离可重复调用的列表拉取逻辑 const fetchPersonList = () => { axios.get('http://localhost:60359/api/person/getpersons').then((res)=>{ setPersonList(res.data); }) } // 首次挂载时拉取数据 useEffect(()=>{ fetchPersonList(); },[]) return ( <div className="app"> <h2>All students <span role="img" aria-labelledby="love">📫</span></h2> <button type="button" className="btn btn-info"onClick={() => navigate('/SavePerson/')}>Add Person</button> <table className="table" > <TableHeader></TableHeader> <tbody> {PersonList&&PersonList.map((student,i) => { return ( <TableRow key={student.id} obj={student} onRefresh={fetchPersonList}></TableRow> ); })} </tbody> </table> </div> ); } export default CrudDemo;
- 修改
TableRow组件,透传刷新回调函数:
function TableRow(props) { return ( <tr > <th>{props.obj.id}</th> <th>{props.obj.personName}</th> <th> { (props.obj.city!=null&&props.obj.city.name.length >0) ? <div> {props.obj.city.name} </div> : <div> </div> } </th> <th>{props.obj.personPhoneNumber}</th> <th> <TableAction id={props.obj.id} onRefresh={props.onRefresh}></TableAction> </th> </tr> ); } export default TableRow
- 修改
TableAction组件,删除成功后直接调用刷新函数,移除多余的同路径跳转:
function TableAction(props) { const navigate=useNavigate(); const handleClick = (e) => { axios.get('http://localhost:60359/api/person/DeletePerson/'+props.id).then((res)=>{ console.log('person deleted message :',res.data); // 删除成功直接拉取最新列表数据 props.onRefresh(); }) }; return ( <div> <button type="button" className="btn btn-info"onClick={() => navigate('/PersonDetail/'+props.id,{state:{id:props.id}})}>Details</button> <button type="button" className="btn btn-danger"onClick={handleClick}>Delete</button> </div> ); } export default TableAction
方案2:保留同路径跳转逻辑,通过依赖变化触发useEffect执行
如果业务要求必须保留跳转同路由的逻辑,可以通过两种方式实现刷新:
- 给路由配置增加动态key,强制导航时重挂载组件:
// 路由配置处修改,每次导航location.key都会生成新值,触发组件重挂载 <Route path="/CrudDemo" element={<CrudDemo />} key={location.key} />
- 修改useEffect依赖项,监听路由变化触发数据拉取:
// CrudDemo组件内修改useEffect useEffect(()=>{ axios.get('http://localhost:60359/api/person/getpersons').then((res)=>{ setPersonList(res.data); }) // 依赖location.key,每次导航到当前页key变化就会重新执行 },[location.key])
使用该方案时,跳转代码建议加replace参数,避免历史栈堆积重复记录:
navigate('/CrudDemo/', {replace: true})
优化建议
- 原代码中声明的
ShouldRefresh状态没有实际使用,可以直接删除减少冗余代码。 - 删除操作建议使用
DELETE请求方法,不要用GET方法触发数据修改,不符合接口规范,也容易被浏览器缓存、爬虫误触发。
内容的提问来源于stack exchange,提问作者Amir Kian
相关产品推荐
相关产品推荐

