React 18严格模式:useMemo创建实例后如何合规清理?
解决React 18严格模式下实例创建与清理的问题
在React 18严格模式的开发环境中,组件会经历「挂载→立即卸载→重新挂载」的流程,用来检测未正确清理的副作用。你之前用useMemo创建实例、useEffect清理的方式,会导致第一次卸载时销毁实例,但第二次挂载时复用已销毁的实例(因为useMemo依赖空数组,不会重新执行),从而引发异常。
改用useState的方案会触发额外渲染,还会返回初始空值,不符合需求。以下是不影响性能、适配严格模式的解决方案:
实现方案
使用useRef存储实例与销毁状态,结合渲染阶段的惰性初始化和useEffect的清理逻辑,既保证实例在渲染时即可使用,又能在严格模式下正确重建实例:
function useFoo() { const fooRef = useRef({ instance: null, isDestroyed: false }); // 渲染阶段惰性初始化:实例不存在或已销毁时,创建新实例 if (!fooRef.current.instance || fooRef.current.isDestroyed) { fooRef.current.instance = createFoo(); fooRef.current.isDestroyed = false; } useEffect(() => { const currentInstance = fooRef.current.instance; return () => { // 清理时销毁当前实例,并标记为已销毁 currentInstance.destroy(); fooRef.current.isDestroyed = true; }; }, []); return fooRef.current.instance; }
原理说明
- 无渲染触发的状态存储:
useRef的修改不会触发组件重渲染,避免额外性能损耗。 - 始终返回有效实例:渲染阶段直接检查实例状态,确保返回的实例不会是空值或已销毁的实例。
- 适配严格模式:严格模式下第一次卸载时,清理函数会销毁实例并标记状态;第二次渲染时会自动创建新实例,保证后续使用的是可用实例。
注意事项
- 如果
createFoo包含副作用(比如创建DOM元素、订阅事件),开发环境下严格模式会触发两次实例创建,但第一次的实例会在清理函数中销毁,仅在开发阶段存在临时资源占用,生产环境不会有此问题。 - 确保
createFoo可以被安全调用多次,每次调用都能生成独立的实例。
内容的提问来源于stack exchange,提问作者Seba Kerckhof
相关产品推荐
相关产品推荐

