Can the setState function prevState be considered mutable?

I know that this.stateit should not be changed directly, it should be used instead setState.

From this, I suggested that prevStateit should also be considered immutable, and instead setStateshould always look something like this:

this.setState((prevState) => {
  // Create a new object instance to return
  const state = { ...prevState };
  state.counter = state.counter + 1;
  return state;
});

Or with a deeper nesting:

this.setState((prevState) => {
  // Create a new object instance to return
  const state = { ...prevState, counter: { ...prevState.counter } };
  state.counter.value = state.counter.value + 1;
  return state;
});

Or just a partial update, for example, from setState({}), where it is easier and more pleasant to use:

this.setState((prevState) => ({ counter: prevState.counter + 1 }));

All of the above is obviously correct, because they return a new instance, but then I came across this question, where the accepted answer encourages mutation prevStatewithout returning a new instance of the object (note the code block in the question).

Something like that:

this.setState((prevState) => {
  prevState.flag = !prevState.flag;
  return prevState;
});

, , prevState this.state:

(JSFiddle)

class Test extends React.Component {
  state = { counter: 0 };

  onDemonstrateButtonClick = (event) => {
    this.setState((prevState) => {
      if (prevState === this.state) alert(`uh, yep`);
      prevState.counter++;
      return prevState;
    });
  };

  render() {
    return (
      <div>
        <button onClick={this.onDemonstrateButtonClick}>Demonstrate</button>
        {this.state.counter}
      </div>
    );
  }
}

, ! ? prevState? , this.state ?

: TypeScript ReadOnly, .

+6
1

prevState setState ?

, prevState, setState

  • prevState . . , prevState .

:

prevState this.state, , , .

, , , prevState , , setState , js prevState, , prevState != this.state

, setState, 1.

setState - async, , setState , setState, prevState, prevState this.state .

, , , , prevState this.state.

class App extends React.Component{
  constructor(props)
  {
    super(props);
    this.state = {
      counter : 1
    };
  }

  increment = () =>{
    this.setState((prevState , props) => {
      console.log("in first"); //3
      console.log(prevState);  //3
      console.log(this.state); //3
      if(prevState == this.state)
      {
         console.log("in first prevState == this.state");
      }
      return {
        counter : prevState.counter+1
      }
    } , ()=>{
      console.log("done updating first"); //5
    });


    console.log("after first"); //1

    this.setState((prevState, props) => {
      console.log("in second"); //4
      console.log(this.state);  //4
      console.log(prevState);   //4
      if (prevState == this.state) {
        console.log("in second prevState == this.state");
      }
      return {
        counter: prevState.counter + 1
      }
    } , () =>{
      console.log("done updating second"); //6
    });

    console.log("after second"); //2

  }

  render(){
    return (
      <div>
        <span>{this.state.counter}</span>
        <br/>
        <button onClick={this.increment} >increment</button>
      </div>
    )
  }
}

"after first"
"after second"
"in first"Object {counter: 1}Object {counter: 1}
"in first prevState == this.state"
"in second"Object {counter: 1}Object {counter: 2}
"done updating first"
"done updating second"

, console.log https://codesandbox.io/s/k325l485mr


, . return return setState

return {
    counter: prevState.counter + 1
}

return {
    counter: this.state.counter + 1
}

, , 1 , , 2 setState, , prevState, this.state

, -

this.setState((prevState) => ({ counter: prevState.counter + 1 }));

+3

Source: https://habr.com/ru/post/1016432/


All Articles