![](/img/trans.png)
[英]Why React js receive multiple answer from server with Socket.io?
[英]Socket.io and React: Proper way too receive data from server and set state in a component?
尝试运行一个基本的聊天应用程序,但在发送消息时遇到过度重新呈现的问题。 这是客户端的适用代码:
const [chatMessages, setChatMessages] = useState([]);
const sendChat = (e) => {
socket.emit("sendMessage", e.target.elements.message.value);
}
useEffect(() => {
socket.on("receiveMessage", (chatMessage) => {
setChatMessages([...chatMessages, chatMessage]);
console.log(chatMessages);
});
}, [chatMessages]);
return (
{chatMessages.map((message) => <p>{message}</p>)}
)
然后,在服务器上:
io.on("connection", (socket) => {
socket.on("sendMessage", (chatMessage) => {
console.log("message sent");
io.to(roomId).emit("receiveMessage", chatMessage);
});
}
当我这样做时,消息已成功发送和接收,但会导致它发生很多次(控制台):
[]
[]
[{...}]
[{...}]
(2) [{...}, {...}]
在第三条消息中,这是记录的内容。 到第六条或第七条消息时,整个页面都停止了,因为它记录了大约 100 次。
我尝试了以下方法:
在useEffect()
中有一个空的依赖数组。 这确实修复了重新渲染,但引入了一个新问题。 最新消息是唯一保存并替换最后一条消息的消息,因此您一次只能看到一条消息。
将其全部从useEffect()
中取出。 这只会使问题恶化,并导致每条消息的重新呈现次数更多。
任何帮助,将不胜感激。 谢谢!
当chatMessages
state 更新但不清除它们时,您正在创建套接字事件处理程序。 如果您编辑您的代码或组件重新呈现等......然后添加另一个套接字事件处理程序。 多个处理程序将开始堆叠并排队多个意外的 state 更新。
此外,由于 React state 更新是异步处理的,您无法在更新排队后立即记录 state 并期望看到更新后的 state。为此使用单独的useEffect
挂钩。
添加useEffect
清理 function 以删除事件处理程序,并在处理程序回调中重新包含更新的chatMessages
state 数组。
useEffect(() => { const handler = (chatMessage) => { setChatMessages([...chatMessages, chatMessage]); } socket.on("receiveMessage", handler); return () => socket.off("receiveMessage", handler); }, [chatMessages]);
添加一个useEffect
清理 function,删除依赖项以便效果在组件安装时运行一次,并使用功能性 state 更新从回调附件中的先前 state 而不是初始 state 正确更新。
useEffect(() => { const handler = (chatMessage) => { setChatMessages(chatMessages => [...chatMessages, chatMessage]); } socket.on("receiveMessage", handler); return () => socket.off("receiveMessage", handler); }, []);
在这两者之间,第二个选项是更优的解决方案,但你选择哪个是你的决定。
要记录聊天消息chatMessages
更新:
useEffect(() => {
console.log(chatMessages);
}, [chatMessages]);
由于您依赖于chatMessages
,每次chatMessages
更改时,它都会创建一个新的侦听器。 这就是为什么当收到更多消息时它变得越来越慢。
你可以做两件事:
useEffect
方法中本地维护chatMessages
。 您可以展开该数组,然后使用展开的数组调用setChatMessages
。 执行此操作时,您可以删除chatMessages
对useEffect
的依赖性,并且仍然拥有所有消息。 作为一种好的做法,您应该返回一个 function,它将在组件卸载时删除事件侦听器。 const [chatMessages, setChatMessages] = useState([]); const sendChat = (e) => { socket.emit("sendMessage", e.target.elements.message.value); } useEffect(() => { let localMessages = []; const callback = (chatMessage) => { localMessages = [...localMessages, chatMessage]; setChatMessages(localMessages); console.log(localMessages); }; socket.on("receiveMessage", callback); return () => { socket.off("receiveMessage", callback); } }, []); return ( {chatMessages.map((message) => <p>{message}</p>)} )
useRef
来存储值。 但是,当值更改时,这不会触发 UI 的重新呈现,这可能不是您想要的。 所以这可能不是一个好的选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.