javascript - React JS状态数组在函数内部为空,但项目出现在渲染中
问题描述
我正在编写这个反应组件以在聊天应用程序中呈现用户的所有聊天。会话列表从 REST 端点获取并设置为状态变量。当一条新消息通过套接字到达时,我试图将列表中的对话置于顶部并用不同的颜色标记它。
代码如下所示:
const [conversationsList, setConversationsList] = useState([]);
//When a new message arrives,
const markNewConversation = (message) => {
console.log(conversationsList); //Empty array
let newConversationList = conversationsList.map((conversationElement) => {
if (conversationElement.thread_id === message.thread_id) {
conversationElement.date_created = message.date_created;
conversationElement.new_for.push(user._id);
}
return conversationElement;
});
console.log(newConversationList);
newConversationList = newConversationList.sortBy(function (o) {
return o.date_created;
});
console.log(newConversationList); //Empty as well.
setConversationsList(newConversationList); //Whole screen goes black on this.
};
useEffect(() => {
if (user._id === null) history.push("/");
connectSocket();
socket.on("_messageIn", markNewConversation);
getThreads().then((threads) => {
threads.forEach((thread, index) => {
let allParticipants = thread.thread_participants;
threads[index].other_user = allParticipants.find((participant) => {
return participant._id != user._id;
});
});
setConversationsList(threads);
setIsLoading(false);
});
// returned function will be called on component unmount
return () => {
socket.off("_messageIn", markNewConversation);
};
}, []);
return conversationsList.map((conversation) => {
return(//magically appears inside this div.)
})
问题是当有新消息到达时,函数接收到一个空数组,整个屏幕都变空了。我什至没有在任何地方将数组设置为空。我哪里错了?
解决方案
javascript中有一个State Mutating的概念,我们永远不应该直接改变对象。在这里,您犯的错误是,当新消息到来时,它会用新消息替换整个对象并重新初始化它。因此,在添加新消息之前使用传播运算符传播状态。这样做:
let newConversationList = conversationsList.map((conversationElement) =>
(conversationElement.thread_id === message.thread_id) ? {
...conversationElement, //spread/copy like this before mutating
date_created: message.date_created,
new_for: [...conversationElement.new_for, user.id]
} : {
...conversationElement, //spread/copy like this before mutating
new_for: [...conversationElement.new_for]
}