【问题标题】:React js pushing new object to array always replace last object instead of insertReact js将新对象推送到数组总是替换最后一个对象而不是插入
【发布时间】:2021-12-28 02:57:31
【问题描述】:

我有消息列表,并附加从套接字接收的实时消息,从套接字插入一个对象,但之后它总是替换最后一个而不是插入新的。

const [chatList, setChatList] = useState(props.chatList ? props.chatList : []);

useEffect(() => {

    const messageListener = (message) => {
        console.log('message',message);
        console.log('chatList',chatList);

        if(message.conversation_id == props.conversation_id){

                const updatedMsgs = [...chatList,message];
                setChatList(updatedMsgs);
        }
        
    };
  
    socket.on('myEventName', messageListener);

    return () => {
      socket.off('myEventName', messageListener);
    };
  }, [props.conversation_id]);

新消息和消息列表日志看起来像

【问题讨论】:

    标签: javascript reactjs react-hooks use-effect use-state


    【解决方案1】:

    看起来像 chatList 状态的陈旧外壳。使用功能状态更新来更新之前的状态,而不是在回调范围内关闭的状态值,setChatList(list => [...list, message]);

    useEffect(() => {
      const messageListener = (message) => {
        console.log('message',message);
        console.log('chatList',chatList);
    
        if (message.conversation_id == props.conversation_id) {
          setChatList(list => [...list, message]);
        } 
      };
    
      socket.on('myEventName', messageListener);
    
      return () => {
        socket.off('myEventName', messageListener);
      };
    }, [props.conversation_id]);
    

    【讨论】:

    • 谢谢@Drew。 setChatList(chatList => [...chatList, message]); 工作...
    【解决方案2】:

    由于 Javascript 中的 Stale Closures 确实会出现此问题。

    Hooks 严重依赖 JavaScript closures。这就是为什么钩子如此富有表现力和简单。但是关闭有时很棘手。

    示例如下:

    function DelayedCount() {
      const [count, setCount] = useState(0);
      function handleClickAsync() {
        setTimeout(function delay() {
          setCount(count + 1);
        }, 1000);
      }
      return (
        <div>
          {count}
          <button onClick={handleClickAsync}>Increase async</button>
        </div>
      );
    }
    

    如果您快速单击按钮 2 次,则计数仅增加 1,而不是 2。

    在每次点击时,setTimeout(delay, 1000) 安排在 1 秒后执行 delay()delay() 将变量 count 捕获为 0。

    delay() closures(因为点击了 2 次)都将状态更新为相同的值:setCount(count + 1) = setCount(0 + 1) = setCount(1)

    都是因为第二次点击的delay() closure将过期的count变量捕获为0。

    为了解决这个问题,我们需要使用函数式的方式setCount(count =&gt; count + 1)来更新计数状态:

    ...
    function handleClickAsync() {
      setTimeout(function delay() {
        setCount(count => count + 1);
      }, 1000);
    }
    ...
    

    现在按钮可以正常工作了。

    这是完整的文章,可以帮助您了解Stale ClosuresArticle Link

    【讨论】:

      猜你喜欢
      • 2017-10-10
      • 2021-04-23
      • 2021-12-03
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-31
      • 2021-11-06
      相关资源
      最近更新 更多