React js将新对象推送到数组总是替换最后一个对象而不是插入
React js pushing new object to array always replace last object instead of insert
我有消息列表,并附加从套接字接收到的实时消息,一个从套接字插入的对象,但之后它总是替换最后一个而不是插入新的。
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]);
新消息和消息列表日志看起来像
看起来像是 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]);
由于 Javascript 中的 Stale Closures
,确实会出现此问题。
Hooks heavily rely on JavaScript closures. That's why hooks are so expressive and simple. But closures are sometimes tricky.
示例如下:
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
捕获了过时的计数变量为 0。
要解决这个问题,我们需要使用函数式方法 setCount(count => count + 1)
来更新计数状态:
...
function handleClickAsync() {
setTimeout(function delay() {
setCount(count => count + 1);
}, 1000);
}
...
现在按钮确实按预期工作了。
这是完整的文章,可以帮助您了解 Stale Closures
。 Article Link
我有消息列表,并附加从套接字接收到的实时消息,一个从套接字插入的对象,但之后它总是替换最后一个而不是插入新的。
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]);
新消息和消息列表日志看起来像
看起来像是 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]);
由于 Javascript 中的 Stale Closures
,确实会出现此问题。
Hooks heavily rely on JavaScript closures. That's why hooks are so expressive and simple. But closures are sometimes tricky.
示例如下:
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
捕获了过时的计数变量为 0。
要解决这个问题,我们需要使用函数式方法 setCount(count => count + 1)
来更新计数状态:
...
function handleClickAsync() {
setTimeout(function delay() {
setCount(count => count + 1);
}, 1000);
}
...
现在按钮确实按预期工作了。
这是完整的文章,可以帮助您了解 Stale Closures
。 Article Link