Reputation: 111
Having tough time trying to update just the "values" property which is a object within an object. I am not super familiar with the reactjs or its shenanigans.
const [properties, setProperties] = useState({})
<Form.Control onChange={e => setProperties(prevState => ({...prevState, values: {a: value}}))}>
<Form.Control onChange={e => setProperties(prevState => ({...prevState, values: {b: value}}))}>
Final object should look like this:
{
x: 1, <-- These have their
y: 2, <-- own inputs
values: {
a: "A value",
b: "B value"
}
}
But currently after typing to one the inputs value A overrides B or vice-versa. I tried searching answers from web, but none concerned updating object's object
Upvotes: 1
Views: 3004
Reputation: 14365
You're close. You have to spread the nested objects properties back into it just like you did with prevState
.
setProperties(prevState => ({...prevState, values: {...prevState.values, b: e.target.value}}))
Spreading prevState
makes a new object out of its values. But when you specify a key to overwrite the values taken from prevState
are gone. Basically, you aren't merging prevState.values
with the new values
. You're overwritting it.
To fix this you need to provide the whole nested object again. The easiest pattern for that is the one above. Spread prevState.values
, then overwrite the nested key you want to change.
Note: If you use an event in a functional update, you need to either save the value to another variable, or use e.persist()
first. The reason is that React reuses event objects for performance reasons, so e
will be reset before the async update happens. using persist
removes the event from the pool for reuse, and you may access its values normally.
Example:
const handleChange = (e) => {
e.persist();
setProperties(prevState => (
{
...prevState,
values: {...prevState.values, b: e.target.value}
}
))
// OR
let value = e.target.value;
setProperties(prevState => (
{
...prevState,
values: {...prevState.values, b: value}
}
))
}
As another note, I only used a functional update in my answer because that is how the question was given. But in this usecase it is not required. You may use a normal state update safely for this handler.
Upvotes: 6
Reputation: 188
The new state is not computed using old values, so you don't need to pass a function to setProperties
. Instead, you can write it simply like this:
const [properties, setProperties] = useState({})
<Form.Control onChange={e => setProperties({ ...properties, values: { ...properties.values, a: e.target.value }})}>
<Form.Control onChange={e => setProperties({ ...properties, values: { ...properties.values, b: e.target.value }})}>
Hope that helps!
Upvotes: 2
Reputation: 4192
import React, {
useState
} from "react";
function Test() {
const [state, setState] = useState({
x: 1,
y: 2,
values: {
a: "A value",
b: "B value"
}
});
const changeA = (e) => {
const val = e.target.value;
setState({...state, a: val})
}
const changeB = (e) => {
const val = e.target.value;
setState({...state, b: val})
}
return (
<div>
<input onChange={changeA}/>
<input onChange={changeB}/>
</div>
);
}
export default Test;
Upvotes: 0