I am working on a chat application using React and socket.io. Back end is express/node. The relevant components are: Room.js --> Chat.js --> Messages.js --> Message.js
messageData received from the server is stored in state in Room.js. It is then passed down through Chat.js to Messages.js, where it is mapped onto a series of Message.js components.
When messages are received, they ARE appearing, but only after I start typing in the form again, triggering messageChangeHandler(). Any ideas why the Messages won't re-render when a new message is received and added to state in Room.js? I have confirmed that the state and props are updating everywhere they should be--they just aren't appearing/re-rendering until messageChangeHandler() triggers its own re-render.
Here are the components.
Room.js
export default function Room(props) {
const [messagesData, setMessagesData] = useState([])
useEffect(() => {
console.log('the use effect ')
socket.on('broadcast', data => {
console.log(messagesData)
let previousData = messagesData
previousData.push(data)
// buildMessages(previousData)
setMessagesData(previousData)
})
}, [socket])
console.log('this is messagesData in queue.js', messagesData)
return(
// queue counter will go up here
// <QueueDisplay />
// chat goes here
<Chat
profile={props.profile}
messagesData={messagesData}
/>
)
}
Chat.js
export default function Chat(props) {
// state
const [newPayload, setNewPayload] = useState({
message: '',
sender: props.profile.name
})
// const [messagesData, setMessagesData] = useState([])
const [updateToggle, setUpdateToggle] = useState(true)
const messageChangeHandler = (e) => {
setNewPayload({... newPayload, [e.target.name]: e.target.value})
}
const messageSend = (e) => {
e.preventDefault()
if (newPayload.message) {
socket.emit('chat message', newPayload)
setNewPayload({
message: '',
sender: props.profile.name
})
}
}
return(
<div id='chatbox'>
<div id='messages'>
<Messages messagesData={props.messagesData} />
</div>
<form onSubmit={messageSend}>
<input
type="text"
name="message"
id="message"
placeholder="Start a new message"
onChange={messageChangeHandler}
value={newPayload.message}
autoComplete='off'
/>
<input type="submit" value="Send" />
</form>
</div>
)
}
Messages.js
export default function Messages(props) {
return(
<>
{props.messagesData.map((data, i) => {
return <Message key={i} sender={data.sender} message={data.message} />
})}
</>
)
}
Message.js
export default function Message(props) {
return(
<div key={props.key}>
<p>{props.sender}</p>
<p>{props.message}</p>
</div>
)
}
Thank you in advance for any help!
setMessagesData([...messageData, data])
? – AlageuseEffect()
doesn't have a dependency onmessagesData
, somessagesData
was changing outsideuseEffect()
but not inside it. More details in my overly-elaborate answer. – Jairia