You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React函数组件state消息数组清空后新增数据时旧数据恢复问题

问题根因

问题出在socket.on('message')的回调存在闭包捕获旧值+直接修改引用类型的问题:

  1. 注册消息监听的useEffect依赖为空数组,仅在组件首次挂载时执行一次,回调函数捕获的msg永远是首次渲染时的初始空数组引用
  2. 回调中let temp = msg后直接执行temp.push(),相当于直接修改了这个被闭包缓存的原始数组,所有历史消息都会被永久存在这个数组里
  3. 执行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 21:06:03