i have a simple react demo where to show websocket messages, but the .map function inside return statements returns nothing. No errors and no messages. Can anyone explain where the problem is in here?
const [messages, setMessages] = React.useState([]) //push the websocket messages response to const messages const addMessage = (message) => { let n = messages; let d = message; n.push(d); setMessages(n) //the following both works as expected messages.map((item) => { console.log('message', item.message) }) messages.map((message, index) => console.log(message,index) ) }
Now the problem in return statement: Here was nothing returned.
return ( <div> { messages.map(function(message, index){ return (<p id={'t'+index}>{message.message}</p>) }), messages.map((message, index) =>{ return (<p id={'z'+index}>{message.message}</p>) }) } </div> )
Maybe the return statement is not rerendered after receiving websocket message? I hope anyone have an idea and can explain the problem.
Advertisement
Answer
Issue
You are mutating the messages
state array by pushing directly into it and saving it back into state. The messages
array reference never changes! React uses shallow object reference equality to help determine when the DOM should be updated. If the reference never updates then React bails on rerendering.
const [messages, setMessages] = React.useState([]) //push the websocket messages response to const messages const addMessage = (message) => { let n = messages; // <-- reference to state let d = message; n.push(d); // <-- state mutation setMessages(n). // <-- saved back into state ... }
Solution
Always shallow copy state that is being updated. Use a functional state update to update from the previous state
const [messages, setMessages] = React.useState([]) //push the websocket messages response to const messages const addMessage = (message) => { setMessages(messages => [ ...messages, // <-- shallow copy messages array message, // <-- and append new message ]) ... }