Last updated: Apr 7, 2024
Reading timeยท3 min
To update nested properties in a state object in React:
setState
to get access to the current state object.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 the spread syntax (...) return { ...current, address: { ...current.address, // ๐๏ธ Override the value for the nested `country` property country: 'Germany', }, }; }); }; return ( <div> <button onClick={updateNestedProps}>Click</button> <h4>{JSON.stringify(employee, null, 4)}</h4> </div> ); }
We used the spread syntax (...) to unpack the key-value pairs of the objects into a new object creating shallow copies.
const employee = { name: 'Alice', address: { country: 'Austria', coords: [1, 2], }, }; const newEmployee = { ...employee, address: { ...employee.address, // ๐๏ธ Override the `country` property country: 'Germany', }, }; // ๐๏ธ newEmployee.address.country is 'Germany' now console.log(newEmployee);
Notice that we aren't directly mutating the state object in any way.
The country
property overrides the property with the same name that exists on
the object because we provided it after using the spread syntax.
We passed a function to setState
because the function is guaranteed to be
invoked with the current (most up-to-date) state.
const updateNestedProps = () => { setEmployee(current => { // ๐๏ธ Using the spread syntax (...) return { ...current, address: { ...current.address, // ๐๏ธ Override the value for nested `country` property country: 'Germany', }, }; }); };
When the next state is computed using the previous state, pass a function to
setState
.
If you get the warning prop spreading is forbidden, click on the link and follow the instructions.
Alternatively, you can create a copy of the nested object and directly update the property on the copy.
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 => { // ๐๏ธ Get the copy of nested object const address = {...current.address}; address.country = 'Germany'; return {...current, address}; }); }; return ( <div> <button onClick={updateNestedProps}>Click</button> <h4>{JSON.stringify(employee, null, 4)}</h4> </div> ); }
This example achieves the same result, however, is a bit more difficult to read and a bit more tricky.
We created a copy of the state.address
object and directly updated the
country
property on the copy.
Then we set the address
property in the new state object to the copy we
updated.
Which approach you pick is a matter of personal preference. I'd go with the first example because it is much more intuitive to simply override the properties we want to update.
I've also written an article on how to update a component's state on click.