In order to set the state of a specific nested field, you have set the whole object. I did this by creating a variable, newState and spreading the contents of the current state into it first using the ES2015 spread operator. Then, I replaced the value of this.state.flag with the new value (since I set flag: value after I spread the current state into the object, the flag field in the current state is overridden). Then, I simply set the state of someProperty to my newState object. Of course this is abusing some core principles, as the state should be read-only, but since you are immediately discarding the old state and replacing it with new state, it is completely ok. If you have deeply nested state, consider if you can restructure the child objects to sit at the root. This makes the data easier to update.
// However, there is a nested state method, which allows to access nested state by name.
// example :-
state = {
user: {
name: {
firstName: 'Kaushal',
lastName: 'Shah'
}
}
};
// To access state =>
state
// To access user =>
state.user or state.nested('user')
// To access name =>
state.user.nested('name')
// To access firstName =>
state.user.nested('name').nested('firstName')
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
}..
}
...
}
...
}
To write it in one line
this.setState({
someProperty: {
...this.state.someProperty,
flag: false
}
});
Approach 2: We can pass the old nested object using the spread operator and then override the particular properties of the nested object. There are the following approaches to update nested state properties in ReactJS: Step to Run Application: Run the application using the following command from the root directory of the project: CS SubjectsMathematicsOperating SystemDBMSComputer NetworksComputer Organization and ArchitectureTheory of ComputationCompiler DesignDigital LogicSoftware Engineering
Creating React Application:
Step 1: Create a React application using the following command:
npx create - react - app foldername
Step 2: After creating your project folder i.e. foldername, move to it using the following command:
cd foldername
Project Structure: It will look like the following.
Approach 1: App.js
import React, { Component } from "react";
class App extends Component {
// Nested object
state = {
name: 'kapil',
address: {
colony: 'vaishnav nagar',
city: 'Jaipur',
state: 'Rajasthan'
}
};
handleUpdate = () => {
// Creating a dummy object using spread operator
var address = { ...this.state.address }
// Updating the city
address.city = 'Kota';
this.setState({ address })
}
render() {
return (
<div style={{ margin: 200 }}>
<h1>{this.state.name}</h1>
<h1>{this.state.address.colony} {","}
{this.state.address.city}{", "}
{this.state.address.state}</h1>
<button
onClick={this.handleUpdate}
>UpdateCity </button>
</div>
);
}
}
export default App;
npm start
Pass a function to setState to get access to the current state object. To update nested properties in a state object in React: When the next state is computed using the previous state, pass a function to setState. We passed a function to setState, because the function is guaranteed to be invoked with the current (most up to date) state.
Copied!import {useState} from 'react';
export default function App() {
const initialState = {
name: 'Alice',
address: {
country: 'Austria',
coords: [1, 2],
},
};
const [employee, setEmployee] = useState(initialState);
const updateNestedProps = () => {
setEmployee(current => {
// 👇️ using spread syntax (...)
return {
...current,
address: {
...current.address,
// 👇️ override value for nested country property
country: 'Germany',
},
};
});
};
return (
<div>
<button onClick={updateNestedProps}>Click</button>
<h4>{JSON.stringify(employee, null, 4)}</h4>
</div>
);
}
Copied!
const employee = {
name: 'Alice',
address: {
country: 'Austria',
coords: [1, 2],
},
};
const newEmployee = {
...employee,
address: {
...employee.address,
// 👇️ override country property
country: 'Germany',
},
};
// 👇️ newEmployee.address.country is 'Germany' now
console.log(newEmployee);
Copied!
const updateNestedProps = () => {
setEmployee(current => {
// 👇️ using spread syntax (...)
return {
...current,
address: {
...current.address,
// 👇️ override value for nested country property
country: 'Germany',
},
};
});
};
The easiest way to update a nested object stored in the Reactjs state is to use the spread operator. I will explain it with several examples. We have a demo Reactjs app that handles a simple personal information form. The form contains the person's information, including address and email address. The address is nested in the person object, and the state and zip are nested in the address object. The stateZip is a nested object residing in the address object. The representation is person -> address -> stateZip. This person object is stored in the state as const [person, setPerson] = useState(initialState)
interface person {
name: string
age: string
address: {
street: string,
city: string,
stateZip: {
state: string,
zip: string
}
}
contact: {
email: string
} []
}
let initialState: person = {
name: "Lance",
age: "36",
address: {
street: "100 Some street",
city: "Edmond",
stateZip: {
state: "Oklahoma",
zip: "73034"
}
},
contact: [{
email: "abc@learnbestcoding.com"
}, {
email: "aab@learnbestcoding.com"
}]
}
//This doesn't work
const updatePersonName = (name: string) => {
person.name = value
setPerson(person)
}
const updateAddress = (event: HTMLInputElement) => {
const {
name,
value
} = event
setPerson((prevPerson) => {
const newPerson = {
...prevPerson
}
if (name === "street" || name === "city") {
newPerson.address[name] = value
}
return newPerson
})
}
const updateStateZip = (event: HTMLInputElement) => {
const {
name,
value
} = event
setPerson((prevPerson) => {
const newPerson = {
...prevPerson
}
if (name === "state" || name === "zip") {
newPerson.address.stateZip[name] = value
}
return newPerson
})
}
There are two main ways to deal with the problem of updating a deeply nested state. First is flattening your state to avoid the problem altogether. The second is using immutable libraries that help with state manipulations. There are libraries out there that are designed to help with immutable updates. For example, here is how Immer can help to reduce our boilerplate. But why is immutability so important if it makes the trivial task of updating a state so complicated? Here are three main reasons from React documentation:
const updateTodo = ({
taskId,
todoId,
value
}) => {
setProject({
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
todos: {
...state.tasks[taskId].todos,
[todoId]: {
value: value
}
}
}
}
})
}
project.tasks[taskId].todos[todoId].value = true
const updateTodo = ({
taskId,
todoId,
value
}) => {
setState(produce(baseState, draftState => {
draftState.tasks[taskId].todos[todoId].value = value
return draftState
}))
}
State can hold any kind of JavaScript value, including objects. But you shouldn’t change objects that you hold in the React state directly. Instead, when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy. In other words, you should treat any JavaScript object that you put into state as read-only. You can store any kind of JavaScript value in state.
const [x, setX] = useState(0);
setX(5);
const [position, setPosition] = useState({
x: 0,
y: 0
});
import { useState } from 'react';
export default function MovingDot() {
const [position, setPosition] = useState({
x: 0,
y: 0
});
return (
<div
onPointerMove={e => {
position.x = e.clientX;
position.y = e.clientY;
}}
style={{
position: 'relative',
width: '100vw',
height: '100vh',
}}>
<div style={{
position: 'absolute',
backgroundColor: 'red',
borderRadius: '50%',
transform: `translate(${position.x}px, ${position.y}px)`,
left: -10,
top: -10,
width: 20,
height: 20,
}} />
</div>
);
}
onPointerMove = {
e => {
position.x = e.clientX;
position.y = e.clientY;
}
}
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. 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. Now, the spread operator creates only one level nested copy of the object. If your state is highly nested like:
I'm trying to organize my state by using nested property like this:
this.state = {
someProperty: {
flag: true
}
}
But updating state like this,
this.setState({
someProperty.flag: false
});
Hello @kartik,
var someProperty = {
...this.state.someProperty
}
someProperty.flag = true;
this.setState({
someProperty
})
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
}
}
}
}))
Pretty uncontroversial up to this point! But what if we have nested state? That is, we need to update a property in our state object one (or more) levels deep? In React, we can update state using state setter functions. In function components, a state setter is provided by the useState hook. Incrementing a count using a button would look like this: If this feels redundant, it’s because it is! One option we have is to create a change handler that handles any property of user. Note that the following example depends on the name attribute of our inputs to map perfectly to our user state object.
import { useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
return (
<button
onClick={() => {
setCount(count + 1);
}}
>
Increment
</button>
);
}
class MyComponent extends React.Component {
constructor() {
this.state = { count: 0 };
}
render() {
return (
<button
onClick={() => {
this.setState({ count: this.state.count + 1 });
}}
>
Increment
</button>
);
}
}
function SignupForm() {
const [user, setUser] = useState({ email: '', password: '' });
return (
<form>
<label htmlFor="email">Email address</label>
<input id="email" name="email" value={user.email} />
<label htmlFor="password">Password</label>
<input id="password" name="password" value={user.password} />
</form>
);
}
<input
id="email"
name="email"
value={user.email}
onChange={(e) => {
setUser({
...user,
email: e.target.value,
});
}}
/>
<input
id="password"
name="password"
value={user.password}
onChange={(e) => {
setUser({
...user,
password: e.target.value,
});
}}
/>
When using setState with a nested object and attempting to update just certain attributes of the state object, an expected state may be obtained, as will be detailed below. Rather of updating a single attribute of the nested state object and expecting Right to merge the objects, just duplicate the original state object and change it before calling setState with the modified copy of the original state object. Build a new state from the original state and the spread operator then call setState again with the updated state.
state = {
fullName: "Bob Fisher",
email: '[email protected]'
}
this.state = {
fullName: "Bob Fisher",
email: '[email protected]'
}
this.setState({
fullName: "Bob Fisher",
email: '[email protected]'
});
var newState = React.addons.update(this.state, {
userInfo: {
email: {
$set: "[email protected]"
}
}
});
this.setState(newState);
const {
userInfo: oldUserInfo
} = this.state;
const userInfo = {
...oldUserInfo,
email: "[email protected]"
};
this.setState({
userInfo
});