Laravel Inertia React中preserveState不生效,页面重载丢失状态
解决Inertia请求后状态重置的问题
1. 用函数式更新状态规避闭包陷阱
你当前的setAllProducts依赖作用域内的allProducts变量,这会导致闭包捕获旧状态值,当Inertia请求完成时,无法获取最新的状态快照。改成函数式更新即可解决:
const fetchProducts = (page) => { Inertia.get( `/products?page=${page}`, { filters }, { preserveState: true, preserveScroll: true, only: ['products'], onSuccess: (response) => { // 通过函数式更新获取最新的前序状态 setAllProducts(prev => prev.concat(response.props.products.data)); } } ) };
2. 将分页页码纳入状态管理
你在onSuccess中修改的page是局部参数,下次调用fetchProducts时仍会传入旧值。应该把页码用useState统一管理:
const [currentPage, setCurrentPage] = useState(1); const fetchProducts = () => { Inertia.get( `/products?page=${currentPage}`, { filters }, { preserveState: true, preserveScroll: true, only: ['products'], onSuccess: (response) => { setAllProducts(prev => prev.concat(response.props.products.data)); setCurrentPage(prev => prev + 1); } } ) };
3. 确认组件未被重复挂载
preserveState: true仅在同一页面组件的导航场景下生效,如果路由配置导致页面组件被卸载后重新挂载(比如路由路径变化但对应组件未复用、嵌套路由层级变更),状态会被强制重置。可以通过以下代码排查组件挂载情况:
useEffect(() => { console.log('组件已挂载'); return () => console.log('组件已卸载'); }, []);
若确实存在重复挂载,可采取两种方案:
- 检查Inertia路由配置,确保分页导航指向同一个页面组件
- 将
filters和allProducts存入本地存储,在组件初始化时恢复:
const [filters, setFilters] = useState(() => { const saved = localStorage.getItem('productFilters'); return saved ? JSON.parse(saved) : []; }); const [allProducts, setAllProducts] = useState(() => { const saved = localStorage.getItem('allProducts'); return saved ? JSON.parse(saved) : []; }); // 监听filters变化并持久化 useEffect(() => { localStorage.setItem('productFilters', JSON.stringify(filters)); }, [filters]); // 按需持久化allProducts useEffect(() => { localStorage.setItem('allProducts', JSON.stringify(allProducts)); }, [allProducts]);
4. 验证请求目标页面的一致性
确保/products?page=${page}对应的后端路由返回的是同一个Inertia页面组件。如果后端渲染了不同的组件,前端状态会被直接重置。
内容的提问来源于stack exchange,提问作者Jenssen
相关产品推荐
相关产品推荐

