reactjsstate

Updating an object with setState in React


Is it at all possible to update object's properties with setState?

Something like:

this.state = {
   jasper: { name: 'jasper', age: 28 },
}

I have tried:

this.setState({jasper.name: 'someOtherName'});

and this:

this.setState({jasper: {name: 'someothername'}})

The first results in a syntax error and the second just does nothing. Any ideas?


Solution

  • There are multiple ways of doing this. Since state update is an async operation, to update the state object, we need to use updater function with setState.

    1- Simplest one:

    First create a copy of jasper then, make the changes in that:

    this.setState(prevState => {
      let jasper = Object.assign({}, prevState.jasper);  // creating copy of state variable jasper
      jasper.name = 'someothername';                     // update the name property, assign a new value                 
      return { jasper };                                 // return new object jasper object
    })
    

    Instead of using Object.assign we can also write it like this:

    let jasper = { ...prevState.jasper };
    

    2- Using spread syntax:

    this.setState(prevState => ({
        jasper: {                   // object that we want to update
            ...prevState.jasper,    // keep all other key-value pairs
            name: 'something'       // update the value of specific key
        }
    }))
    

    Note: Object.assign and Spread Operator create only shallow copy, so if you have defined nested object or array of objects, you need a different approach.


    Updating nested state object:

    Assume you have defined state as:

    this.state = {
      food: {
        sandwich: {
          capsicum: true,
          crackers: true,
          mayonnaise: true
        },
        pizza: {
          jalapeno: true,
          extraCheese: false
        }
      }
    }
    

    To update extraCheese of pizza object:

    this.setState(prevState => ({
      food: {
        ...prevState.food,           // copy all other key-value pairs of food object
        pizza: {                     // specific object of food object
          ...prevState.food.pizza,   // copy all pizza key-value pairs
          extraCheese: true          // update value of specific key
        }
      }
    }))
    

    Updating array of objects:

    Let;s assume you have a todo app, and you are managing the data in this form:

    this.state = {
      todoItems: [
        {
          name: 'Learn React Basics',
          status: 'pending'
        }, {
          name: 'Check Codebase',
          status: 'pending'
        }
      ]
    }
    

    To update the status of any todo object, run a map on the array and check for some unique value of each object. In case of condition=true, return the new object with updated value, else same object.

    let key = 2;
    this.setState(prevState => ({
    
      todoItems: prevState.todoItems.map(
        el => el.key === key? { ...el, status: 'done' }: el
      )
    
    }))
    

    Suggestion: If object doesn't have a unique value, then use array index.