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?
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
}
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') });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With