export const Component = () => {
const [messages, setMessages] = useState([]);
const sendMessage = msg => {
socket.emit('message', msg);
setMessages([
...messages,
{
content: msg.content
}
])
};
const onMessage = msg => setMessages([
...messages,
{
content: msg.content
}
]);
useEffect(() => {
socket.on('message', onMessage)
}, []);
return (
<button onClick={() => sendMessage({content: 'test'})}/>
)
};
这是我如何实现发送/获取消息的示例代码。问题是,如果我从套接字(onMessage)获取消息,则总是重新渲染消息。一切都很好,如果我通过sendMessage
函数执行此操作,则消息会充满。
谢谢!
编辑: 我已经解决了这个问题,有答案:
useEffect(() => {
socket.on('message', onMessage)
}, [messages]); //rerender if messages changed
但是我不明白为什么这可以解决我的问题。有人可以解释吗?
编辑2:
useEffect(() => {
socket.on('message', onMessage)
return () => {
socket.off('message', onMessage);
}
}, [messages]); //rerender if messages changed
您如何看待该解决方案?
答案 0 :(得分:0)
您的问题是一个简单的closure
案例,当您在初始加载期间将事件侦听器方法设置为套接字时,onMessage
甚至与其词法范围都在使用。但是,在下一个后续渲染期间,将创建一个新的onMessage及其更新的词法作用域,该词法作用域不会重新分配给socket event
,因此它将引用其中的messages
值,该值在初始加载期间就存在。 >
但是,如果您编写要在每次消息更改时执行的效果,则会将针对消息更改重新呈现而创建的新onMessage方法分配给套接字事件,并且该方法可以正常工作。
但是,比在状态messages
中使用useEffect
作为依赖项更好的解决方案是使用状态更新回调
const onMessage = msg => setMessages(prevMessages => ([
...prevMessages,
{
content: msg.content
}
]));
useEffect(() => {
socket.on('message', onMessage)
return () => {
socket.off('message', onMessage);
}
}, []);