Search code examples
reactjsimmutability

Updating state - why creating a new copy of state when calling setState?


React docs:

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

That's clear.

class App extends React.Component {
  state = {
   data: []
  } 

the following I understand

  updateState(event) {
   const {name, value} = event.target;
   let user = this.state.user; // this is a reference, not a copy...
   user[name] = value; // 
   return this.setState({user}); // so this could replace the previous mutation
  }

this following I don't understand

  updateState(event) {
  const {name, value} = event.target;
  let user = {...this.state.user, [name]: value};
  this.setState({user});
  }

I understand (as in previous example), that I should not either only:

  1. mutate state directly without calling setState; or
  2. mutate it and then use setState afterwards.

However, why can't I just (without direct mutation) call setState without creating a new copy of state (no spread operator/Object.assign)? What would be wrong with the following:

  getData = () => {
   axios.get("example.com") ...
    this.setState({
     data:response.data
    })
  } 

Why should it be:

  getData = () => {
   axios.get("example.com") ...
    this.setState({
     data:[...data, response.data]
    })
  } 

 render (){ 
  ...
 }  
}

Solution

  • What would be wrong with the following:

    this.setState({
       data: response.data,
    });
    

    Absolutely nothing, unless you don't want to replace the contents of this.state.data with response.data.

    Why should it be:

    this.setState({
       data: [...data, response.data],
    });
    

    Because with spread you are not loosing the contents of this.state.data - you are basically pushing new response into the data array.

    Note: You should use callback inside setState to get access to current data from this.state.

    this.setState((prevState) => ({
       data: [...prevState.data, response.data],
    }));