简体   繁体   中英

React re-render not showing updated state array

I am updating state(adding new object to state array) in event handler function.

const handleIncomingData = (data) => {
  setState(state => {
    var _state = state
    if (_state.someDummyStateValue === 1234) {
      _state.arr.push({ message: data.message })
    }
    return _state
  })
}

React.useEffect(() => {
  socket.on('data', handleIncomingData)
  return()=>{
    socket.off('data', handleIncomingData)
  }
},[])

I am updating state in this manner as event handler function is not having access to latest state values. console.log(state) shows updated state but after re-render newly added object is not displayed. Also when same event fires again previously received data is displayed but not the latest one. Is there something wrong with updating state in this manner?

Object in javascript are copied by reference (the address in the memory where its stored). When you do some thing like:

let obj1 = {}
let obj2 = obj1;

obj2 has the same reference as obj1 .

In your case, you are directly copying the state object. When you call setState , it triggers a re-render. React will not bother updating if the value from the previous render is the same as the current render. Therefore, you need to create a new copy of your state.

Try this instead:

setState(prevValue => [...prevValue, {message: data.message}])

To better illustrate my point here's a codesandbox: https://codesandbox.io/s/wild-snowflake-vm1o4?file=/src/App.js

Try using the default way of making states it is preferred, clean and simple codeing way

const [message, setMessage] = useState([])
const handleIncomingData = data => {
   let newMessage = message;
    if (data.message.somevalue === 1234){ 
       newMessage.push(data.message);
       setMessage(newMessage)
    }
}
React.useEffect(() => {
  socket.on('data', handleIncomingData)
  return()=>{
    socket.off('data', handleIncomingData)
  }
},[message])

Yes, it's wrong... You should never do operations directly in the state... If you want to append messages to your array of messages, the correct snippet code would be:

const [messages, setMessage] = useState([])
const handleIncomingData = useCallback(
    data => {
        if (messages.someDummyStateValue === 1234) {
           setMessage([...messages,{message:data.message}])
        }
        // do nothing

},[messages])

React.useEffect(() => {
  socket.on('data', handleIncomingData)
  return()=>{
    socket.off('data', handleIncomingData)
  }
},[handleIncomingData])

This way I'm not doing any operation to any state, I'm just replace the old state, with the new one (which is just the old one with a new message)

Always you want to manipulate data in an array state, you should never do operations directly in the state...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM