使用直接链接访问路由时如何确保react-redux store数据已填充完成?
解决方案
你可以根据业务场景选择以下任意一种方案实现,也可以组合使用增强稳定性:
方案1:根组件全局加载拦截
在根组件渲染路由之前等待全局数据加载完成,所有路由统一走加载校验,适合全局数据量不大的场景:
// App.jsx 根组件代码示例 import { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { fetchAllProducts } from './store/productSlice' import { Switch, Route, Redirect } from 'react-router-dom' import MainView from './MainView' import SingleProduct from './SingleProduct' function App() { const dispatch = useDispatch() const [isDataLoaded, setIsDataLoaded] = useState(false) const loadError = useSelector(state => state.product.loadError) useEffect(() => { dispatch(fetchAllProducts()) .unwrap() .then(() => setIsDataLoaded(true)) .catch(() => setIsDataLoaded(false)) }, [dispatch]) // 加载中展示占位 if (!isDataLoaded && !loadError) return <div>资源加载中...</div> // 加载失败跳转首页 if (loadError) return <Redirect to="/" /> return ( <Switch> <Route path="/" exact> <MainView /> </Route> <Route path="/product/:id"> <SingleProduct /> </Route> <Route> <Redirect to="/" /> </Route> </Switch> ) }
方案2:自定义路由守卫做局部校验
封装专属路由组件,只给需要依赖全局数据的路由加校验,不影响其他页面的加载速度:
// DataRequiredRoute.jsx 自定义路由组件 import { useSelector } from 'react-redux' import { Route } from 'react-router-dom' function DataRequiredRoute({ children, ...rest }) { const isProductsLoaded = useSelector(state => state.product.isLoaded) return ( <Route {...rest} render={() => isProductsLoaded ? children : <div>数据加载中,请稍候...</div> } /> ) } // 路由配置替换对应路由即可 <Switch> <Route path="/" exact> <MainView /> </Route> <DataRequiredRoute path="/product/:id"> <SingleProduct /> </DataRequiredRoute> <Route> <Redirect to="/" /> </Route> </Switch>
方案3:组件内做兜底兼容
不需要改动上层逻辑,仅修改SingleProduct组件即可实现,成本最低,适合快速修复问题:
// SingleProduct.jsx 代码示例 import { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useParams, Redirect } from 'react-router-dom' import { fetchAllProducts } from './store/productSlice' function SingleProduct() { const { id } = useParams() const dispatch = useDispatch() const { products, isLoaded, loadError } = useSelector(state => state.product) const currentProduct = products.find(item => item.id === id) useEffect(() => { // 未加载数据时主动触发拉取 if (!isLoaded && !loadError) { dispatch(fetchAllProducts()) } }, [isLoaded, loadError, dispatch]) if (!isLoaded) return <div>商品数据加载中...</div> if (loadError || !currentProduct) return <Redirect to="/" /> // 正常渲染商品详情 return ( <div> <h1>{currentProduct.name}</h1> <p>{currentProduct.description}</p> </div> ) }
优化建议
如果全局商品数据量较大,全量预加载会拖慢首屏速度,可以直接调整逻辑取消全局预加载,改为在SingleProduct组件中根据路由id单独请求对应商品数据,性能和稳定性都会更好。
内容的提问来源于stack exchange,提问作者MadOgre
相关产品推荐
相关产品推荐

