如何在React严格模式下正确结合useState与useEffect?
解决React严格模式下useConst Hook的重复执行问题
我编写了一个Hook,用于一次性生成值,并可在组件卸载时(可选)清理该值:
function useConst(fn, cleanup) { const [value] = useState(fn); useEffect( () => () => { cleanup?.(value); }, [value] ); return value; }
但这个Hook在React严格模式下无法正常工作——副作用会执行两次。我尝试过基于useRef和useMemo的变体,但它们在严格模式下同样失效。
问题根源
React严格模式在开发环境中会刻意重复执行组件的挂载/卸载流程,用来检测潜在的资源泄漏或逻辑问题:
useState的初始化函数fn会被调用两次(React会忽略第二次的返回值,保留首次结果)。useEffect的清理函数会在模拟卸载时执行一次,待组件重新挂载后,真正卸载时又执行一次,导致清理逻辑被重复触发。- useRef/useMemo的实现方案要么会让
fn重复执行,要么无法避免清理逻辑的重复触发。
修复方案
以下是适配严格模式的useConst实现,确保fn只执行一次,且清理逻辑仅在真正的组件卸载时触发:
function useConst(fn, cleanup) { const valueRef = useRef(null); const mountCount = useRef(0); // 仅在首次挂载时执行值生成逻辑 if (mountCount.current === 0) { valueRef.current = fn(); } useEffect(() => { mountCount.current += 1; return () => { mountCount.current -= 1; // 仅当挂载次数归0(真正卸载)时执行清理 if (mountCount.current === 0 && cleanup) { cleanup(valueRef.current); valueRef.current = null; // 可选:重置引用,避免内存泄漏 } }; }, [cleanup]); return valueRef.current; }
方案说明
- 用
mountCount跟踪组件挂载次数,确保值生成函数fn仅在组件首次挂载时执行,严格模式下的重复挂载不会重新生成值。 - 清理逻辑仅在挂载次数归0时触发,规避了严格模式下模拟卸载导致的重复清理问题,同时保证生产环境正常卸载时的清理逻辑生效。
内容的提问来源于stack exchange,提问作者David S
相关产品推荐
相关产品推荐

