Reputation: 753
I'm trying to incorporate WebSockets into a React chat application, and upon receiving a message from the backend and adding it the messages
array, the array just overwrites the first value and stays at a size of one instead of incrementing. I don't seem to know why, as when the client sends a message, that message is appended to the array and it grows as expected, but when that same client receives a message, the array is cleared out and all the messages except for the one that came in is gone. How do I fix this?
import './App.css';
import { useState, useEffect } from "react"
const socket = new WebSocket("ws://localhost:8080/ws");
function App() {
const [messages, setMessages] = useState([])
const [inputValue, setInputValue] = useState("")
useEffect(() => {
socket.onopen = () => {
console.log("connected")
}
socket.onmessage = msg => {
const parsedMessage = JSON.parse(msg.data)
//The array is never incremented when the client receives a message. Messages
//added by the client through the input are erased when this function is invoked.
setMessages([...messages, {className: "other-message", body: parsedMessage.body}])
};
socket.onclose = event => {
console.log("Socket Closed Connection: ", event);
};
socket.onerror = error => {
console.log("Socket Error: ", error);
};
}, [])
const addMessage = () => {
socket.send(inputValue);
//Here, messages are appended to the array as expected.
setMessages([...messages, {className: "message", body: inputValue}])
setInputValue("")
}
console.log("messages", messages);
return (
<div className="App">
<h1>Chat</h1>
<div className='chat-window'>
{
messages.map((message, i) => {
return <div key={i} className={message.className}>{message.body}</div>
})
}
</div>
<div className='input-wrapper'>
<input value={inputValue} onChange={e => setInputValue(e.target.value)}/>
<button onClick={addMessage}>Send</button>
</div>
</div>
);
}
export default App;
Upvotes: 0
Views: 241
Reputation: 17397
You have a closure, so the value of messages is always the initial value of an empty array. Change your code so that you're getting the current value of messages each time:
socket.onmessage = msg => {
const parsedMessage = JSON.parse(msg.data)
setMessages((prevState) => [...prevState, {className: "other-message", body: parsedMessage.body}])
};
Upvotes: 1