Reputation: 61
Currently I have the following code:
export default function Chat() {
const [chat, setChat] = useState({ ID: 0, messages: [] })
const {socket} = useContext(SocketContext)
useEffect(() => {
socket.on('/chat', (message) => {
setChat({...chat, messages: [...chat.messages, message] }
//Some other interaction with variables inside this Chat function (eg: document.getElementById)
}
}, [])
return <div>{chat.toDivs()}</div>
}
But this doesn't work as expected, because the useEffect always uses the same value of chat. So the result of receiving a message on /chat will always be [message] instead of [...prevMessages, message].
I have searched about this problem and people suggested to use componentDidMount(), but since I'm not using React.Component extendable class, I can't use that method.
Is there any good, simple solution for this?
Upvotes: 2
Views: 510
Reputation: 202667
Use a functional state update so you are updating from the previous state and not the state value closed over in callback scope.
Don't forget to also unsubscribe when unmounting to clean up resources.
const [chat, setChat] = useState({ ID: 0, messages: [] });
useEffect(() => {
const onChat = (message) => {
setChat(chat => ({
...chat,
messages: [...chat.messages, message],
}));
};
socket.on('/chat', onChat);
return () => socket.off('/chat', onChat);
}, []);
Upvotes: 3