React严格模式下如何让useEffect清理仅在组件卸载时执行?
解决React严格模式下useEffect清理函数提前执行的问题
React严格模式会触发组件的双重渲染,导致空依赖数组的useEffect清理函数在组件刚挂载时就执行一次,之后卸载时再执行一次。比如你写的这段代码:
useEffect(() => { return () => { console.log('do you only call once?') // TODO: Fix why this is resetting to init state when I ENTER instead of just leave // dispatch(resetToInitialState()) } }, [])
原本期望清理逻辑只在页面退出时执行,结果刚进入页面就触发了,导致之前设置的状态被提前重置。下面是几种不用关闭严格模式就能解决的方案:
方案1:用Ref标记首次挂载(最稳妥)
利用useRef记录组件是否完成首次挂载,只在真正卸载时执行清理逻辑:
import { useEffect, useRef } from 'react'; // 在组件内部定义 const isMounted = useRef(false); useEffect(() => { // 组件挂载完成后标记 isMounted.current = true; return () => { // 只有挂载完成后,才执行目标清理逻辑 if (isMounted.current) { console.log('只在卸载时执行'); // dispatch(resetToInitialState()) } // 重置标记,避免内存泄漏 isMounted.current = false; }; }, []);
原理:严格模式的第一次渲染会快速执行后卸载,此时isMounted.current还没被设为true,所以跳过清理逻辑;第二次渲染完成后标记为已挂载,当组件真正卸载时,才会执行你需要的操作。
方案2:通过路由监听替代(更贴合业务)
如果你的清理逻辑是为了离开当前页面时重置状态,可以直接监听路由变化,只有当离开当前页面时才执行:
import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; // 组件内部 const location = useLocation(); const currentPath = '/your-page-path'; // 替换成当前页面的路由路径 useEffect(() => { return () => { // 检查路由是否离开当前页面 if (location.pathname !== currentPath) { console.log('离开页面时执行'); // dispatch(resetToInitialState()) } }; }, [location, currentPath]);
这种方式从业务逻辑出发,完全避开了严格模式双重渲染的影响,推荐优先考虑。
方案3:判断严格模式环境(不推荐)
可以通过React内部的环境变量判断是否处于严格模式,但这个变量是非公开的,未来可能失效,仅作参考:
useEffect(() => { const isStrictMode = process.env.NODE_ENV === 'development' && window.__REACT_STRICT_MODE__; return () => { // 非严格模式下才执行 if (!isStrictMode) { console.log('执行清理'); // dispatch(resetToInitialState()) } }; }, []);
内容的提问来源于stack exchange,提问作者wanna_coder101
相关产品推荐
相关产品推荐

