Firebase Realtime Database嵌套.on监听器如何使用.off()完成清理?
解决Firebase Realtime Database嵌套.on()监听器的清理问题
核心思路是在useEffect的作用域内维护一个内层监听器的清理队列,每次外层child_added触发新建内层监听器时,就将对应监听器的销毁逻辑存入队列,最终在useEffect的清理回调中批量执行队列里的所有销毁逻辑即可。
具体实现步骤
- 在useEffect内部声明一个空数组,用于存储所有内层thread监听器的清理函数
- 每次创建threadRef的value监听器后,将该监听器的
off操作、keepSynced关闭操作封装为函数,推入上述数组 - 在useEffect的最终清理回调中,遍历数组执行所有清理函数,再处理外层ChannelRef的清理
修改后的完整代码示例
useEffect(() => { const ChannelRef = database().ref(`/user/${uid}/channel`); // 存储所有内层thread监听器的清理函数 const threadCleanupTasks = []; ChannelRef.keepSynced(true); ChannelRef.on('child_added', channel_id => { const startTime = .... const threadRef = database().ref(`/channel/${channel_id.key}/Thread`).orderByKey().startAt(startTime); threadRef.keepSynced(true); // 单独声明回调,方便后续精准销毁,避免误清同节点的其他监听器 const threadValueCallback = thread => { dispatch({ type: 'AddThread', payload: thread.val() }); }; threadRef.on('value', threadValueCallback); // 将当前thread监听器的清理逻辑推入队列 threadCleanupTasks.push(() => { threadRef.off('value', threadValueCallback); threadRef.keepSynced(false); }); }) return () => { // 先清理所有内层thread监听器 threadCleanupTasks.forEach(cleanup => cleanup()); // 再清理外层channel监听器 ChannelRef.off(); ChannelRef.keepSynced(false); } // 补充依赖项避免闭包问题 }, [uid, dispatch])
额外注意事项
如果后续你需要监听channel节点的child_removed事件,可在对应回调中单独找到要销毁的thread监听器执行清理,不需要等到组件卸载。
内容的提问来源于stack exchange,提问作者Chavalit Laohaudomphan
相关产品推荐
相关产品推荐

