Student
Student

Reputation: 1975

Is it ok to modify part of prevState inside setState?

Is there a real disadvantage to modifying part of prevState and returning that part inside setState() ?

Example:

this.setState(prevState => {
    prevState.myObject.isItTrue = !prevState.myObject.isItTrue;
    return {myObject: prevState.myObject};
});

Rather than:

this.setState(prevState => {
    const myObject = Object.assign({}, prevState.myObject);
    myObject.isItTrue = !myObject.isItTrue;
    return {myObject: myObject};
});

Is there any real disadvantage to the first code where I save myself the Object.assign() ?

EDIT: If I am correct, prevState.myObject is simply a reference to this.state.myObject, so changing prevState.myObject actually changes this.myObject.object as well! However, this doesn't seem to break anything, as long as I use setState() to pass an object that contains the new data, even if it's just a reference to the old objects inside this.state. Do you agree that this is still ok, i.e. it won't break anything to do it like this?

Upvotes: 4

Views: 713

Answers (2)

Jose A. Ayllón
Jose A. Ayllón

Reputation: 886

Following documentation:

state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state and props.

https://reactjs.org/docs/react-component.html

So you should not apply changes directly to that state.

Either way, why not do something like this?:

this.setState(prevState => ({
    myObject : {
        ...prevState.myObject,
        isItTrue: !prevState.myObject.isItTrue,
    }
}));

This way will get all the elements from the prevState but also change all the ones you want to modify.

Upvotes: 7

Gabriele Petrioli
Gabriele Petrioli

Reputation: 196026

First prevState and the this.state are the same object. So you are modifying the actual state directly.

Secondly, down the road you might pass the myObject as a prop to another component, and since it will be the same object always that component will not know that something has changed and it will not re-render (for example PureComponent and ones that implement componentDidUpdate or shouldComponentUpdate and test for changes)

See https://codesandbox.io/s/zen-aryabhata-m07l4 for showcases of all issues.

So you should use

this.setState(state => ({
      myObject: {
        ...state.myObject,
        isItTrue: !state.myObject.isItTrue
      }
    }));

Upvotes: 4

Related Questions