Using JavaScript’s spread operator is all well and god, but doing so when updating complex types in React can be an eyesore. That is, it just get unwieldy because I often have to spread objects properties which are themselves objects.
In the following example, UserProfile.Address
is a nested object that we want to update when a button is clicked. You can see how I need to spread the nested object to get access to its members when calling the setUser
state function.
import { useState } from 'react';
const UserProfile = () => {
const [user, setUser] = useState({
id: 1,
name: 'John Doe',
role: 'Administrator',
email: 'johndoe@example.com',
dateAdded: '2024-09-17',
address: {
street: '123 Main St',
}
})
const updateUser = () => {
const newStreetAddress = '456 Main St';
setUser({...user, address: {...user.address, street: newStreetAddress}});
}
return (
<>
<h2>User Profile</h2>
<p>ID: {user.id}</p>
<p>Name: {user.name}</p>
<p>Role: {user.role}</p>
<p>Email: {user.email}</p>
<p>Date Added: {user.dateAdded}</p>
<p>Address: {user.address.street}</p>
<button onClick={() => updateUser()}>Update User</button>
</>
)
}
export default UserProfile
The immure package can help us simplify this code to something a bit more intuitive. After installing the ‘immer’ package and importing its produce()
function, we get a different experience.
import { useState } from 'react';
import { produce } from 'immer';
const UserProfile = () => {
const [user, setUser] = useState({
id: 1,
name: 'John Doe',
role: 'Administrator',
email: 'johndoe@example.com',
dateAdded: '2024-09-17',
address: {
street: '123 Main St',
}
})
const updateUser = () => {
const updatedUser = produce(user, draftUser => {
draftUser.address.street = '456 Main St';
});
setUser(updatedUser);
}
return (
<>
<h2>User Profile</h2>
<p>ID: {user.id}</p>
<p>Name: {user.name}</p>
<p>Role: {user.role}</p>
<p>Email: {user.email}</p>
<p>Date Added: {user.dateAdded}</p>
<p>Address: {user.address.street}</p>
<button onClick={() => updateUser()}>Update User</button>
</>
)
}
export default UserProfile
immer is designed to work exclusively with immutable state and provides a nice clean way to work with nested object structures. Even flat object updates benefit from the ability to