2

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?

0

3 Answers 3

2

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

Sign up to request clarification or add additional context in comments.

6 Comments

The reason why I am updating state in that way is because I am doing certain condition checks on other state values and if they are satisfied then only I want to append new data. And for that I need latest state values which are not available in event handler functions
Create a new copy of the message array, so, you can do something like this. var _state = [...state} @RahulJain
@RahulJain check the following example: codesandbox.io/s/wild-snowflake-vm1o4?file=/src/App.js
After seeing your sandbox code, I changed var _state = state to var _state = {...state} and it worked. Can you please explain what could be the reason?
I'll update the answer to explain why it happened. In the meantime, can you mark it as the correct answer so it can help others. @RahulJain
|
0

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])

2 Comments

This way, you'll only have the last message in your state, I'm guessing it's not the goal
The condition check is not on data but on state values and for that I need latest state values.
0

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...

6 Comments

The reason why I am updating state in that is because I am doing certain condition checks on other state values and if they are satisfied then only I want to append new data. And for that I need latest state values which are not available in event handler functions.
No problems, you can still be using any validation you might want in this way, aren't you? Could provide an example?
Ok, I got it, You just need to access the message's actual value, do your validation, if you have a valid data, append it.
One issue with this solution, I wont be getting latest state values as this is event handler function and I am using functional components.
Well done. I think you are right, to solve it you should wrap your handleIncomeData, with the hook, useCallback, and add the 'message' state, to its dependency... I updated my answer
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.