How to Update Nested State Properties in React

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.

Update Nested Objects in React Native using setState

There were few issues:

  1. JSX component name editNested should start with a capital letter.

  2. And editNested component should be on its own function, should not define inside another component which caused your TextInput to lose focus after each render cycle.

  3. The setState call should be changed like below:

const updateNestedObject = (text) => {
setState((prevState) => ({
...prevState,
nested: prevState.nested.map((item) =>
item.id === nestedObject.id ? { ...item, value: text } : item
)
}));
};

Try the code below:

import React, { useState } from "react";
import { View, TextInput, Text, StyleSheet, Button, Alert } from "react-native";

function EditNested({ nestedObject, setState }) {
const updateNestedObject = (text) => {
setState((prevState) => ({
...prevState,
nested: prevState.nested.map((item) =>
item.id === nestedObject.id ? { ...item, value: text } : item
)
}));
};

return (
<View>
<Text>{nestedObject.title}</Text>
<TextInput
style={styles.input}
onChangeText={updateNestedObject}
value={nestedObject.value}
/>
</View>
);
}

function ObjectScreen() {
const [state, setState] = useState({
id: 1,
name: "Test Object",
nested: [
{
id: 1,
title: "Object 1",
value: ""
},
{
id: 2,
title: "Object 1",
value: ""
}
]
});

console.log(state);

return (
<>
<Text>{state.name}</Text>

{state.nested.map((nestedObject, key) => {
return (
<EditNested
key={key}
nestedObject={nestedObject}
setState={setState}
/>
);
})}
</>
);
}

const styles = StyleSheet.create({
container: {},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10
}
});

export default ObjectScreen;

Working Demo

Edit goofy-river-uy5z9e

update nested state object with array inside

You can create an array latestSomeOtherProperty, update the wanted index and then;

const latestSomeOtherProperty = someOtherProperty.map(prop=>{...prop, test: false}); // it updates all but you can put condition here

this.setState(prevState => ({
...prevState,
someProperty: {
...prevState.someProperty,
someOtherProperty: [
...latestSomeOtherProperty
]
}
}))

Updating deeply nested state with useState not working properly

You're breaking one of the primary rules of React state: You're modifying a state object directly, rather than making a copy.

To correctly do the update, you'd do this:

const select = (e) => {
const i = e.target.getAttribute('data-index');
setItems((prevState) => {
// Copy the array (your code was doing that)
const update = [...prevState];
const item = update[i];
// Copy the object (your code wasn't doing that) and update its
// `selected` property
update[i] = {...item, selected: !item.selected};
return update;
});
};

Note how both the array and the object are copied, rather than just the array.

Updating Nested Object in React State

If it is only for 1 level nested object, you could try the following:

  onChangeNest = (e) => {
let targetName = e.target.name
if (targetName.includes(".")) {
let splt = targetName.split(".")
let oldObj = {...this.state[splt[0]]}
oldObj[splt[1]] = e.target.value
this.setState({ [splt[0]]: oldObj })
} else {
this.setState({ [targetName]: e.target.value })
}
}

How to update nested object state in React

The problem is in onPress, you are mutating the option state directly. Because of that the option state keeps the same reference in memory. Now even if you change something, react does not know if it should re-render and decides to nor re-render.
The solution to this problem is to create a copy of the state, so that we have a new reference to work with. In this copy we can modify it as we like and then set the new reference as option state. Now react re-renders since it detects a new reference.

The code could look like this:

            onPress={() =>
setOption(oldOption => {
const newOptions = [...oldOption];
newOptions[i] = { ...newOptions[i], isSelected: !newOptions[i].isSelected};
return newOptions;
})


Related Topics



Leave a reply



Submit