When using a controlled HTML tag in React.
About the snippet below:
Why this works:
OPTION #1
Here event
(onChange) is a synthetic event
. React
re-uses synthetic event
s, which means when the function execution completes, it nullifies the event
properties in the event pool.
Since setState
is async
and event
gets nullified after onChange
is invoked, directly accessing event properties (i.e event.target.value
) within the async callback won't work.
One way is to store the value from a synthetic event
into a variable like:
function changeSelect(event) {
const newValue = event.target.value; // reference
setNestedState((prevState) => {
return({
...prevState,
propA: newValue // can use event properties
});
});
}
Another way to make it work asynchronously is to use event.persist()
.
From the docs,
If you want to access the event properties in an asynchronous way, you should call
event.persist()
on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code.
function changeSelect(event) {
event.persist(); //This will persist the event
setNestedState((prevState) => {
return({
...prevState,
propA: event.target.value
});
});
}
Demo
As correct as ravibagul91 is, I think you are taking a convoluted route to do a relatively simple thing and you aren't really taking advantage of how state actually works.
First, are you getting anything out of having propB in the same state object as propA? From the code, it doesn't seem like it and it's not a bad idea to manage propA and propB in separate states.
That said, you can call the set method for a state directly from the select because it doesn't appear like you need to know anything about the previous state.
function App() {
const [propA,setPropA] = React.useState('');
const [propB,setPropB] = React.useState('');
return(
<React.Fragment>
<div>Prop A: {propA}</div>
<div>Prop B: {propB}</div>
<select
value={propA}
onChange={e => setPropA(e.target.value)}
>
<option value='foo1'>foo1</option>
<option value='foo2'>foo2</option>
<option value='foo3'>foo3</option>
</select>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
Much easier to read, understand, and maintain IMO.