React中多个API订阅怎么在卸载组件时全部清理?
在开发聊天室组件时用了3个WebSocket订阅,但发现组件卸载后后台还是有数据在接收。尝试在useEffect的返回函数里写了unsubscribe,但有时候某个订阅没关干净导致内存泄漏,有没有更好的统一清理方法?
现在这样写的:
useEffect(() => {
const unsub1 = api.subscribe('messages', handleMessages);
const unsub2 = api.subscribe('typing', handleTyping);
const unsub3 = api.subscribe('status', handleStatus);
return () => {
unsub1();
unsub2();
unsub3();
};
}, []);
但最近遇到组件频繁切换时,偶尔出现unsubscribe is not a function的报错,可能是订阅未正确初始化?有没有更健壮的管理方式?
unsubscribe可能是undefined或者被重复调用的问题。你现在的写法其实逻辑没错,但缺了两层防护:
第一,得确保每个
unsub是个函数再调用;第二,得防止组件多次卸载/重载时重复清理同一个订阅(虽然
useEffect的清理函数理论上只执行一次,但实际中可能因为 React 18 严格模式或热更新调试导致执行多次)。最简单的办法是把所有
unsubscribe放进一个数组里,返回前统一调用,同时加个保护:不过更推荐的是封装一个统一的订阅管理器,比如写个
useMultiSubscription的 hook,把订阅逻辑抽出来,避免每次重复写。比如:然后用的时候:
调试看看,如果还是报
unsubscribe is not a function,八成是api.subscribe在某些异常情况下没返回值,比如网络断开时直接返回undefined,这种就得去查下api.subscribe的实现,或者给它包一层兜底逻辑,比如:这样至少不会崩,内存泄漏的问题也能规避掉。
这样就算某些订阅没有正确初始化也不会报错,而且能保证所有订阅都被清理。