Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React setState for nested object while preserving class type

Extending from this question React Set State For Nested Object

The way to update nested state is to decompose the object and re-construct it like the following:

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

However, this is a problem for me, as it will not preserve the component class (More detail below). I am aiming for my state to be structured like the following:

this.state = {
    addressComponent: {
        street: '',
        number: '',
        country: ''
    },
    weather: {
        /* some other state*/
    }
}

To make my life easier, I created a simple address class that builds the object for me and have some other utility function such as validation.

class AddressComponent {
    constructor(street, number, country) {
        this.street = street;
        this.number = number;
        this.country = country;
    }

    validate() {
        if (this.street && this.number, this.country) {
            return true;
        }
        return false;
    }
}

This allows me to do is change the initialization of state to be:

this.state = {
    addressComponent : new AddressComponent(),
    weather: new WeatherComponent();
 }

 this will allow my view component to perform nice things like

if (this.state.addressComponent.validate()) {
    // send this state to parent container
}

The problem with this approach is that if I want to mutate one single piece of information like country and use the above Stack Overflow approach such as:

this.setState({addressComponent: {...addressComponent, country: 'bluh'}})

Doing this will mean that the resolting addressComponent is no longer part of AddressComponent class hence no validate() function

To get around it I cound recreate a new AddressComponent class every time like:

this.setState({addressComponent: new AddressComponent(this.state.street, this.state.number, 'bluh');

But this seems weird.

Am I doing this wrong? Is there a better approach? Is it acceptable to use classes like this with react?

like image 541
user172902 Avatar asked Dec 05 '25 11:12

user172902


2 Answers

It's undesirable to use anything but plain objects for React state to avoid situations like this one. Using class instances will also make serialization and deserialization of the state much more complicated.

The existence of AddressComponent isn't justified, it doesn't benefit from being a class.

The same code could be rewritten as functional with plain objects:

const validateAddress = address => !!(street && address.number && address.country);
...

if (validateAddress(this.state.address)) {
    // send this state to parent container
}
like image 137
Estus Flask Avatar answered Dec 07 '25 23:12

Estus Flask


I think what you said about reinstantiating your class each time you update it in your state is the cleanest way to ensure your validate() method is called at that time. If it were me, I would probably write it as:

const { addressComponent } = this.state;
this.setState({ addressComponent: new AddressComponent(addressComponent.street, addressComponent.number, 'bluh') });
like image 35
Kevin M. Lapio Avatar answered Dec 08 '25 00:12

Kevin M. Lapio