Home > OS >  React setState : unable to update state object
React setState : unable to update state object

Time:01-21

I am struggling to understand why setState in this case is not able to update state object. Below is a simple example of my issue.

class Temp extends Component<TempProps, TempState> {
  constructor(props: TempProps) {
    super(props);
    this.state = { 1: "apple", 2: "banana", 3: "pineapple" };
  }
 
  onBtnClick = () => {
    this.setState(
      (prevState) => {
        const newState = { ...prevState };
        delete newState["2"];
        console.log(newState); //{ 1: "apple", 3: "pineapple" }
        console.log(newState === prevState); //false
        return newState;
      },
      () => {
        console.log(this.state); //{ 1: "apple", 2: "banana", 3: "pineapple" }
      }
    );
  };
  render() {
    return (
      <button onClick={this.onBtnClick}>click me</button>
    );
  }
}
export default Temp;

Why setState() in onBtnClick() is not able to update the state object, even though prevState===newState is false? I'm so confused... thanks a lot for the comments!

CodePudding user response:

The issue is that this.setState() performs a merge of current state and supplied value. So that the new state is like this newState = { ...oldState, ...suppliedValue }. This means that any properties omitted in the new argument will be left unchanged. That's why you could call setState({ b: 22 }) on a state currently having { a: 11, b: 12 } and the new state would be a merge of the supplied value and old value: {a: 11, b: 22}. The fact that you omitted the property: a in the supplied value won't delete it from the final state.

So the only workarounds that I know of are:

  1. Assign a nullish value to the property you want to delete, like null or undefined. This is ugly, but might serve for your needs. For eg, this.setState(prevState => ({ ...prevState, b: undefined }))
  2. Don't assign your app's state directly to this.setState but to a nested property. Something like:
. . .
constructor(props: TempProps) {
    super(props);
    this.state = { appState: { 1: "apple", 2: "banana", 3: "pineapple" } };
  }

. . .

onBtnClick = () => {
    this.setState(
      (prevState) => {
        const newState = { ...(prevState.appState) };
        delete newState["2"];
        console.log(newState); //{ 1: "apple", 3: "pineapple" }
        console.log(newState === prevState); //false
        return { appState: newState };
      },
      () => {
        console.log(this.state); //{ 1: "apple", 3: "pineapple" }
      }
    );
  };
. . .

CodePudding user response:

You can compare two object like this.

JSON.stringify(Object A) === JSON.stringify(Object B)
  •  Tags:  
  • Related