如何在react-router-dom与react-redux项目中避免路由切换时组件重复渲染
React路由切换重复请求与卡顿优化方案
注意:你当前的代码存在命名冲突问题,侧边栏组件和首页组件都使用了
Home作为函数名,会导致路由渲染异常,建议先将侧边栏组件重命名为Sidebar避免冲突。
一、避免重复发起请求的方案
方案1:请求前增加数据存在性判断(无需额外依赖,改动最小)
在dispatch请求前先判断Redux中对应的数据源是否已存在,有数据则跳过请求,以Home组件为例修改如下:
function Home(){ const dispatch = useDispatch(); const homeData = useSelector((data) => data.homeData); React.useEffect(() => { // 仅当homeData为空时才发起请求 if (!homeData?.length) { dispatch(getHomeDataAction) } },[dispatch, homeData]) return ( <> { homeData.map((res) => <span key={res.id}>{res.title}</span>) } </> ) }
About组件按照相同逻辑修改即可,该方案不需要调整路由架构,改造成本最低。
方案2:路由组件持久化(保留组件完整状态)
如果除了避免重复请求之外,还需要保留组件的临时状态(比如表单输入值、滚动位置),可以使用路由缓存方案,React Router v5可通过react-activation库实现KeepAlive功能,路由代码改造如下:
import { AliveScope, KeepAlive } from 'react-activation' function Rutas(){ return ( <Provider store={store}> <AliveScope> <Router> <Switch> <Route exact path="/"> <KeepAlive> <Home /> </KeepAlive> </Route> <Route path="/about"> <KeepAlive> <About /> </KeepAlive> </Route> </Switch> </Router> </AliveScope> </Provider> ) }
改造后路由切换时组件不会被卸载,useEffect只会在首次挂载时执行一次,不会重复触发请求。
二、渲染卡顿优化方案
重复请求只是卡顿的诱因,核心问题是大数据量下列表重渲染开销过高,可做以下优化:
- 给列表项增加唯一key属性:你当前的map方法没有给子元素加key,React Diff时会全量重建DOM,开销极高,按照上面示例代码用数据的唯一字段(比如id)作为key即可大幅降低Diff开销。
- 采用虚拟滚动:如果单页渲染数据超过100条,可使用
react-window实现虚拟滚动,只渲染可视区域内的列表项,DOM节点数量可降低90%以上,渲染耗时会大幅缩短。 - 组件粒度拆分:将列表项拆分为独立组件,用
React.memo包裹,避免无关状态更新触发列表项的不必要重渲染。
内容的提问来源于stack exchange,提问作者Arnel Cariaga Jr.
相关产品推荐
相关产品推荐

