Storing an object in state of a React component?

JavascriptReactjs

Javascript Problem Overview


Is it possible to store an object in the state of a React component? If yes, then how can we change the value of a key in that object using setState? I think it's not syntactically allowed to write something like:

this.setState({ abc.xyz: 'new value' });

On similar lines, I've another question: Is it okay to have a set of variables in a React component such that they can be used in any method of the component, instead of storing them in a state?

You may create a simple object that holds all these variables and place it at the component level, just like how you would declare any methods on the component.

Its very likely to come across situations where you include a lot of business logic into your code and that requires using many variables whose values are changed by several methods, and you then change the state of the component based on these values.

So, instead of keeping all those variables in the state, you only keep those variables whose values should be directly reflected in the UI.

If this approach is better than the first question I wrote here, then I don't need to store an object in the state.

Javascript Solutions


Solution 1 - Javascript

  1. this.setState({ abc.xyz: 'new value' }); syntax is not allowed. You have to pass the whole object.

     this.setState({abc: {xyz: 'new value'}});
    

    If you have other variables in abc

     var abc = this.state.abc;
     abc.xyz = 'new value';
     this.setState({abc: abc});
    
  2. You can have ordinary variables, if they don't rely on this.props and this.state.

Solution 2 - Javascript

You can use ES6 spread on previous values in the object to avoid overwrite

this.setState({
     abc: {
            ...this.state.abc,
            xyz: 'new value'
           }
});

Solution 3 - Javascript

In addition to kiran's post, there's the update helper (formerly a react addon). This can be installed with npm using npm install immutability-helper

import update from 'immutability-helper';

var abc = update(this.state.abc, {
   xyz: {$set: 'foo'}
});

this.setState({abc: abc});

This creates a new object with the updated value, and other properties stay the same. This is more useful when you need to do things like push onto an array, and set some other value at the same time. Some people use it everywhere because it provides immutability.

If you do this, you can have the following to make up for the performance of

shouldComponentUpdate: function(nextProps, nextState){
   return this.state.abc !== nextState.abc; 
   // and compare any props that might cause an update
}

Solution 4 - Javascript

this.setState({abc: {xyz: 'new value'}}); will NOT work, as state.abc will be entirely overwritten, not merged.

This works for me:

this.setState((previousState) => {
  previousState.abc.xyz = 'blurg';
  return previousState;
});

Unless I'm reading the docs wrong, Facebook recommends the above format. https://facebook.github.io/react/docs/component-api.html

Additionally, I guess the most direct way without mutating state is to directly copy by using the ES6 spread/rest operator:

const newState = { ...this.state.abc }; // deconstruct state.abc into a new object-- effectively making a copy
newState.xyz = 'blurg';
this.setState(newState);

Solution 5 - Javascript

Easier way to do it in one line of code

this.setState({ object: { ...this.state.object, objectVarToChange: newData } })

Solution 6 - Javascript

Even though it can be done via immutability-helper or similar I do not wan't to add external dependencies to my code unless I really have to. When I need to do it I use Object.assign. Code:

this.setState({ abc : Object.assign({}, this.state.abc , {xyz: 'new value'})})

Can be used on HTML Event Attributes as well, example:

onChange={e => this.setState({ abc : Object.assign({}, this.state.abc, {xyz : 'new value'})})}

Solution 7 - Javascript

If you want to store an object in the state using functional components you can try the following.

import React from 'react';
import {useState, useEffect} from 'react';

const ObjectState= () => {
    const [username, setUsername] =  useState({});

    const usernameSet = () => {
        const name = {
            firstname: 'Naruto',
            familyname: 'Uzmaki' 
        }
        setUsername(prevState => name);
    }

    return(
        <React.Fragment>
            <button onClick= {usernameSet}>
                Store Object
            </button>
           {username.firstname} {username.familyname} 
        </React.Fragment>
    )
}

export default ObjectState;

If you want to add an object to a pre-existing object.

import React from 'react';
import {useState, useEffect} from 'react';

const ObjectState= () => {
    const [username, setUsername] =  useState({village: 'Konoha'});

    const usernameSet = () => {
        setUsername((prevState) => {
            const data = {
                ...prevState, 
                firstname: 'Naruto',
                familyname: 'Uzmaki' 
            }
            return data
        });
    }

    return(
        <React.Fragment>
            <button onClick= {usernameSet}>
                Store Object
            </button>
            {username.village} {username.firstname} {username.familyname} 
        </React.Fragment>
    )
}

export default ObjectState;

P.S. : Naming the component 'Object' leads to an 'Maximum call stack size exceeded error'. Other names are fine but for some reason 'Object' is not. Like the following is not ok.

    const Object = () => {
        // The above code
    };

    export default Object;

If anyone knows why or how to prevent it please add it to the comments.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRahul DoleView Question on Stackoverflow
Solution 1 - JavascriptkiranView Answer on Stackoverflow
Solution 2 - JavascriptPranavPinarayiView Answer on Stackoverflow
Solution 3 - JavascriptBrigandView Answer on Stackoverflow
Solution 4 - JavascriptjasonseminaraView Answer on Stackoverflow
Solution 5 - JavascriptKevin DanikowskiView Answer on Stackoverflow
Solution 6 - JavascriptOgglasView Answer on Stackoverflow
Solution 7 - JavascriptManil MallaView Answer on Stackoverflow