React组件卸载后WeakMap里的DOM引用没被回收怎么办?
在React项目里用WeakMap存DOM引用,但发现组件卸载后内存没降下来。比如这样写的:
const domRefs = new WeakMap();
function MyComponent() {
const ref = useRef(null);
useEffect(() => {
ref.current = document.createElement('div');
domRefs.set(MyComponent, ref.current); // 用组件做键
return () => domRefs.delete(MyComponent);
}, []);
return <div>...</div>;
}
按理说WeakMap的键是弱引用,组件卸载后应该自动清理才对啊。我试过改成WeakSet也一样没用,内存监控工具显示domRefs里还是存着旧的DOM节点。难道是用组件本身当键有问题?还是说…
之前以为WeakMap会自动处理引用,现在搞不明白哪里出错了。是不是需要手动清理所有相关引用?或者WeakMap的使用场景根本不适合这种缓存?
MyComponent本身,而函数对象在整个应用生命周期中是不会被销毁的,所以WeakMap里的值永远不会被自动清理。我的做法是改用组件实例作为键,而不是组件函数。React函数组件每次渲染都会生成新的实例,这些实例在组件卸载后会被销毁,这样WeakMap才能正常工作。下面是修改后的代码:
这里我把键从
MyComponent换成了ref对象,因为useRef返回的ref对象是和组件实例绑定的,组件卸载时它也会被销毁,这样WeakMap就能正确清理对应的值了。另外,如果你发现内存还是没降下来,可能是因为你在别的地方也持有了这个DOM节点的引用。比如某些全局变量、事件监听器或者其他数据结构也可能偷偷占用了它。建议你仔细检查一下代码,确保没有其他地方意外地保留了对这些DOM的引用。
最后吐槽一句,WeakMap看着挺美好,但实际用起来坑还不少,特别是涉及到React这种函数式组件的场景,稍不注意就容易踩坑。希望这次的改动能帮你解决问题!