如何让组件卸载时派发的Redux action在旧页面useEffect执行前更新到store
问题根因
该时序问题是React默认的Effect执行顺序导致的:同级组件路由切换时,新组件的普通useEffect挂载回调执行时机,早于旧组件的普通useEffect清理回调执行时机,所以PageB卸载时的Redux action派发晚于PageA的初始化逻辑。
解决方案
有三类可落地的方案,按改动成本从低到高排序:
方案1:将PageB的清理逻辑迁移到useLayoutEffect
useLayoutEffect的清理回调会在React提交阶段同步执行,优先级远高于普通useEffect,会在新组件的普通useEffect执行前跑完,仅需修改PageB一行代码即可:
const PageB = () => { // 把原来的useEffect换成useLayoutEffect useLayoutEffect(()=>{ return () => dispatch(SomeReduxAction()) }, []) return .... }
注意:不要在
useLayoutEffect清理函数中执行过重的同步逻辑,避免阻塞页面渲染。
方案2:调整PageA的执行时机,增加Redux状态依赖
把PageA初始化逻辑依赖的Redux状态加入useEffect依赖数组,增加判断仅在状态符合预期后再执行逻辑:
const PageA = () => { // 假设SomeReduxAction会更新redux中的pageBClosed状态 const pageBClosed = useSelector(state => state.xxx.pageBClosed) useEffect(()=>{ // 增加判断,等PageB的清理action执行完成再跑业务逻辑 if (pageBClosed) { doXXXX() } }, [pageBClosed]) return .... }
方案3:在路由前置守卫中派发action
将清理action的派发逻辑从组件生命周期移到路由跳转前置钩子中,所有离开PageB的跳转都会先执行action更新store,再执行组件切换流程,从根源上避免时序问题。
以React Router v6为例,可以用useBeforeLeave钩子实现:
const PageB = () => { useBeforeLeave(() => { dispatch(SomeReduxAction()) }) return .... }
内容的提问来源于stack exchange,提问作者Jeff Peng
相关产品推荐
相关产品推荐

