Reactjs - How to Update Nested and "Normal" State Properties

How to update nested state properties in React

In order to setState for a nested object you can follow the below approach as I think setState doesn't handle nested updates.

var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})

The idea is to create a dummy object perform operations on it and then replace the component's state with the updated object

Now, the spread operator creates only one level nested copy of the object. If your state is highly nested like:

this.state = {
someProperty: {
someOtherProperty: {
anotherProperty: {
flag: true
}
..
}
...
}
...
}

You could setState using spread operator at each level like

this.setState(prevState => ({
...prevState,
someProperty: {
...prevState.someProperty,
someOtherProperty: {
...prevState.someProperty.someOtherProperty,
anotherProperty: {
...prevState.someProperty.someOtherProperty.anotherProperty,
flag: false
}
}
}
}))

However the above syntax get every ugly as the state becomes more and more nested and hence I recommend you to use immutability-helper package to update the state.

See this answer on how to update state with immutability-helper.

ReactJS - how do I update nested and "normal" state properties?

React setState is an asynchronous process - you don't know exactly when it will be updated, you can only schedule the update.

To achieve your desired functionality, you can provide a callback into the setState method.

this.setState({ btnLabel: 'Fetching data...' }, () => console.log(this.state.fetchPriceBtn))

You can learn more following the documentation on the method.

React.js : Updating State of Nested Object

You basically have to create a new empty array of knowledgeTypes and use the current state to find which item of the state you need to change using Object.keys/map/filter functions.

You'd use the current state in a variable and modify that variable only. You'd likely not mess with the actual state object in any way.

After you have done that, simply append it to the empty array. Then you can setState() the new array to the actual state property.

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
financialYear: "2019-20",
quarter: "Q1",
isCurrentQuarter: true,
knowledgeTypes: [
{
knowledgeTypeName: "Technology",
knowledgeItems: [
{
knowledgeItemName: "Java",
subItems: [
{
subItemId: "2",
subItemName: "Collections",
evaluation: {
self: {
ntnet: "Joe",
rating: 1,
isEditable: true
}
}
}
]
}
]
}
]
};
}

handleClick = e => {
const { knowledgeTypes } = this.state;

// transformation
const itemToChange = knowledgeTypes.map(item => {
if (item.knowledgeTypeName === "Technology") {
return item;
}
});
const currItems = itemToChange[0].knowledgeItems[0].subItems;
const subItem = currItems.map(item => {
if (item.subItemId === "2") {
return item;
}
});
const person = subItem[0].evaluation;
person.self.rating = 55; //change

const newKnowledgeTypes = [];
knowledgeTypes.map(item => {
if (item.knowledgeTypeName === "Technology") {
newKnowledgeTypes.push(itemToChange);
}
newKnowledgeTypes.push(item);
});

this.setState({
knowledgeTypes: newKnowledgeTypes
});

console.log(this.state);
};

render() {
return (
<div>
MyComponent
<button onClick={this.handleClick}>Hello</button>
</div>
);
}
}


The sandbox can be found on https://codesandbox.io/s/musing-dew-8r2vk.

Note: It is advisable you do not use nested state objects because state objects are something more lightweight so that they do not have performance considerations.

How to update property state without using this

You can try something like this in your setter functions.

const updateCompleted = (e) => {
setEditedTask((currentState) => ({
...currentState,
[e.target.name]: !e.target.value
})
)};

This solution will give you your previous state, which your can use to update your state.

React hooks: How do I update state on a nested object with useState()?

You need to use spread syntax to copy the font object properties too. Also while trying to update current state based on previous, use the callback pattern

<RadioButtonGroup
onChange={(event) => {
setStyle(prevStyle => ({
...prevStyle,
font: { ...prevStyle.font, align: event.target.value }
}));
console.log(style);
}}
/>

Update state with Nested object in Form

There's a lot of correct answers to this problem. Here is one:

Modify your change handler to accept a curried parameter informing it which nested object to update.

The new handler would looks something like this:

const handleInputChanges = level => e => {
if (!level) {
// Assume root level
setCar({
...car,
[e.target.name] : e.target.value
})
} else {
setCar({
...car,
[level]: {
...car[level],
[e.target.name] : e.target.value
}
})
}
};

Then modify your form like this:

<InputText
type="text"
name="brand"
placeholder="Brand"
value={name}
onChange={handleInputChanges()} // Root level
/>

<InputText
type="text"
name="address"
placeholder="Address"
value={location.address}
onChange={handleInputChanges('location')} // location object
/>

<InputMask
mask="(xxx)-xxx-xxxx"
name="phone"
placeholder="Phone Number"
value={contact.phone}
onChange={handleInputChanges('contact')} // contact object
/>

This is just an example of each type, you'll need to modify each field.

React update a component from another in a nested element

Lifting state up

From the React docs

Often, several components need to reflect the same changing data. We
recommend lifting the shared state up to their closest common
ancestor. Let's see how this works in action.

In this case, it may be possible to move the state from component B to Main. This would be passed through the props to both components A and B, so that they both reflect the changes in state. If the state needs to be updated by component B, for example, from an onClick event, this can be done by passing a callback from Main to component B as shown already by Luke.

How to update state of specific object nested in an array

You can use the index of the array to do a O(1) (No iteration needed) lookup, get the site from the array, add the property to the object, update the array and then set the state with the array. Remeber, map has 3 parameters that can be used (value, index, array).

UPDATE: Fixed Some Typos

class Site{  constructor(text, scdText, key, visible=true)  {    this.text = text;    this.secondaryText = scdText;    this.key = key;    this.isVisible = visible;  }}
class App extends React.Component { constructor(props) { super(props); this.state = { mySites: [ new Site("Oil Site 1", "Fracking", 3), new Site("Oil Site 2", "Fracking", 88), new Site("Oil Site 3", "Fracking", 12), new Site("Oil Site 4", "Fracking", 9) ], } this.clicked = this.clicked.bind(this); }; //Change to a normal function clicked(ind) { //Get the sites from state let stateCopy = {...this.state} let {mySites} = stateCopy; let oilSite = mySites[ind]; //Get site by index //Add property to site oilSite.isVisible = false; mySites[ind] = oilSite;//update array //Update the state this.setState(stateCopy);
}
render = () => ( <div className="wraper"> <div className="oilsites"> {this.state.mySites.map((site, ind) => ( //Add another parameter to map, index <OilSite {...site} onClick={() => this.clicked(ind)} /> ))} </div> </div> )};

ChartJs/React how to update state of nested object within a nested object

You update objects in datasets variable like this

const { chartData } = this.state;
chartData.datasets.map((set) => {
set.fill = true;
});
this.setState({
chartData: chartData,
});



Related Topics



Leave a reply



Submit