React函数组件state消息数组清空后新增数据时旧数据恢复问题
问题根因
问题出在socket.on('message')的回调存在闭包捕获旧值+直接修改引用类型的问题:
- 注册消息监听的
useEffect依赖为空数组,仅在组件首次挂载时执行一次,回调函数捕获的msg永远是首次渲染时的初始空数组引用 - 回调中
let temp = msg后直接执行temp.push(),相当于直接修改了这个被闭包缓存的原始数组,所有历史消息都会被永久存在这个数组里 - 执行
setMsg([])只是将组件state的msg替换为新的空数组,闭包内缓存的旧数组并没有被清空,下次收到新消息时还是会基于存了所有旧数据的旧数组生成新state,导致已删除的旧消息全部重现。
修复方案
将socket消息监听的state更新逻辑改为函数式更新,直接获取最新的state处理,不需要依赖闭包捕获的msg变量:
找到对应代码:
socket.on('message', data => { let temp = msg; console.log('incoming message from server', data.message); rsa .decrypt(new Uint8Array(data.message), pv, 'SHA-256') .then(dec => { // console.log(dec); let dec_msg = new TextDecoder().decode(dec); // console.log(dec_msg); temp.push({ sender: data.name, message: dec_msg, time: moment.utc(Date.now()).local().format('h:mm a'), id: gen_name(1024), }); setMsg([...temp]); }) .catch(e => console.log(e)); divRef.current.scrollIntoView({behavior: 'smooth'}); });
替换为:
socket.on('message', data => { console.log('incoming message from server', data.message); rsa .decrypt(new Uint8Array(data.message), pv, 'SHA-256') .then(dec => { let dec_msg = new TextDecoder().decode(dec); // 函数式更新直接获取最新的msg状态,规避闭包问题 setMsg(prevMsg => [ ...prevMsg, { sender: data.name, message: dec_msg, time: moment.utc(Date.now()).local().format('h:mm a'), id: gen_name(1024), } ]); divRef.current?.scrollIntoView({behavior: 'smooth'}); }) .catch(e => console.log(e)); });
可选优化
- 新增可选链
?.避免ref为空时抛出报错 - 全局声明的
pb、pv、serverKey如果不需要多实例共享,建议放到组件内部用useRef存储,避免多组件实例冲突 - 离开房间时可以手动调用
socket.off('message')移除监听,避免残留逻辑触发
内容的提问来源于stack exchange,提问作者Dark Matter
相关产品推荐
相关产品推荐

