In JavaScript programs, we often have to deal with object values.
Therefore, we’ll often have to create object states and update them.
In this article, we’ll look at how to update object states in our React components.
Merging Objects
The main way to update object states with new property values is to merge the old object with new properties.
For instance, we can write:
import { useState } from "react";
export default function App() {
const [name, setName] = useState({
firstName: "",
middleName: "",
lastName: ""
});
return (
<div className="App">
<input
value={name.firstName}
type="text"
onChange={(e) =>
setName((name) => ({ ...name, firstName: e.target.value }))
}
name="firstName"
placeholder="first name"
/>
<br />
<input
value={name.middleName}
type="text"
onChange={(e) =>
setName((name) => ({ ...name, middleName: e.target.value }))
}
name="middleName"
placeholder="middle name"
/>
<br />
<input
value={name.lastName}
type="text"
onChange={(e) =>
setName((name) => ({ ...name, lastName: e.target.value }))
}
name="lastName"
placeholder="last name"
/>
</div>
);
}
We have the name
state which is set to an object as its initial value.
Below that, we added 3 input elements.
Each of them have the onChange
prop set to a function that calls setName
.
We pass a callback into the setName
function that takes the name
parameter, which has the current value of the name
state.
And it returns an object that copies the name
‘s properties with the spread operator.
And then we set add the property that we want to change at the end of it.
It has to be at the end so that the new property overwrites the property value that already exists in the original state.
e.target.value
has the inputted value.
We can also reduce repetition by creating a function that returns a function that changes the property we want.
To do this, we write:
import { useState } from "react";
export default function App() {
const [name, setName] = useState({
firstName: "",
middleName: "",
lastName: ""
});
const handleChange = (field) => {
return (e) => setName((name) => ({ ...name, [field]: e.target.value }));
};
return (
<div className="App">
<input
value={name.firstName}
type="text"
onChange={handleChange("firstName")}
name="firstName"
placeholder="first name"
/>
<br />
<input
value={name.middleName}
type="text"
onChange={handleChange("middleName")}
name="middleName"
placeholder="middle name"
/>
<br />
<input
value={name.lastName}
type="text"
onChange={handleChange("lastName")}
name="lastName"
placeholder="last name"
/>
</div>
);
}
We have the handleChange
function that returns our state change functions.
It takes the field
parameter, which we use as the property name by passing it into the brackets in the returned object in the setName
callback.
Conclusion
We can use the useState
hook with objects by passing in a callback to our state change functions that returns the copy of the existing state object and set the property to the value we want after that.