ReactJS路由重定向后组件state未更新需手动刷新问题
你当前的列表拉取逻辑写在App.js的空依赖useEffect中,这个钩子仅会在App组件首次挂载时执行一次。前端路由跳转是组件层面的切换,不会触发根组件App卸载重载,因此从/add-item路径跳回首页时,不会重新发起列表请求,内存中保存的items状态始终是首次加载的旧数据,只有手动刷新页面触发整个应用重新挂载,才会重新拉取最新数据。
另外你的代码存在两个会直接导致运行异常的笔误:
useState定义的状态变量名为item,后续更新时调用的是setItems,命名不匹配- React要求自定义组件必须大写开头,
getItems、addItem这类小写开头的写法会被框架识别为原生HTML标签,无法正常渲染
根据你的项目场景选一种实现即可。
方案1:提交成功后触发列表刷新(数据一致性最高)
把列表拉取逻辑抽成独立函数,通过props传给新增页组件,新增提交成功后先调用刷新方法同步父组件状态,再执行路由跳转。
修改后的App.js核心代码:
// 修正状态名笔误 const [items, setItems] = useState([]); // 抽离独立的列表拉取函数 const fetchItemList = () => { axios.get('localhost:3000/api/get_all.php') .then(response => { setItems(response.data); }).catch(error => { console.log(error) }) } // 首次挂载时拉取一次列表 useEffect(() => { fetchItemList(); }, []) return ( <BrowserRouter> <div className="container"> <Routes> {/* 修正组件名为大写开头 */} <Route path="/" element={<GetItems items={items}/>} /> {/* 把刷新函数作为参数传给新增组件 */} <Route path='/add-item' element={<AddItem onSubmitSuccess={fetchItemList} />} /> </Routes> </div> </BrowserRouter> )
对应修改addItem.js的提交逻辑:
import { useNavigate } from 'react-router-dom'; const AddItem = ({ onSubmitSuccess }) => { const navigate = useNavigate(); const onSubmit = (event) => { // 阻止表单默认提交跳转行为 event.preventDefault(); const item = { // 填写你的表单项字段 } axios.post('localhost:3000/api/add_item.php', item) .then(response => { console.log(response.data); // 先刷新父组件列表状态 onSubmitSuccess(); // 再跳回首页 navigate('/'); }) .catch(error => { console.log(error); }) } // 组件其余渲染逻辑 }
记得同步把两个组件的文件名、导出的组件名改为大写开头的GetItems、AddItem,符合React组件命名规范。
方案2:本地拼接新增数据(无额外请求,体验更好)
如果你的新增接口会返回新增完成的完整条目数据,可以不用二次拉取全量列表,直接把新数据拼接到现有items状态中即可:同样将setItems方法通过props传入AddItem组件,提交成功后执行setItems(prev => [...prev, response.data返回的新条目])再跳转,能减少一次接口请求,页面更新更快。
方案3:监听路由变化自动刷新(适合多新增入口场景)
如果项目里有多个入口会修改列表数据,不想逐个传回调,可以借助react-router-dom提供的useLocation钩子监听路径变化,只要回到首页路径就自动拉取最新列表:
// App.js中引入 import { useLocation } from 'react-router-dom'; const location = useLocation(); useEffect(() => { // 仅在首页路径下触发列表拉取 if(location.pathname === '/'){ fetchItemList(); } // 把路径作为依赖项,路径变化时自动执行 }, [location.pathname])
这种写法不需要修改新增组件的逻辑,只要从其他页面跳回首页就会自动刷新列表,维护成本更低。
内容的提问来源于stack exchange,提问作者alizoubair

