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.