I have a form on my website with a default value of ethExperienceLevel set to "BEGINNER". I have a function to change the selected state when I switch between options in a select element dropdown list with an onChange handler. However, e.target.value of the selected element is always the currently selected option’s value, but when I am setting that to ethExperienceLevel on the form the value gets set to one option that was previously selected before the onChange. I do not understand why.
const [form, setForm] = useState<IHackerInput>({
email: '',
firstName: '',
lastName: '',
website: '',
github: '',
linkedIn: '',
yearsOfSoftwareExperience: 0,
ethExperienceLevel: 'BEGINNER',
motivation: 'ATTENDWORKSHOPS',
priorBuilds: '',
lookingToBuild: '',
rulesAccepted: false,
})
const handleETHExperienceSelect = (
e: ChangeEvent<HTMLSelectElement>,
): void => {
if (
e.target.value === 'BEGINNER' ||
e.target.value === 'INTERMEDIATE' ||
e.target.value === 'EXPERT'
) {
console.log(e.target.value) // correctly selected option value
setForm({ ...form, ethExperienceLevel: e.target.value })
console.log(form.ethExperienceLevel) // option before selected change
}
}
<label
htmlFor="ethExperienceLevel"
>
What's your experience level with Ethereum?
</label>
<select
id="ethExperienceLevel"
onChange={(e) => handleETHExperienceSelect(e)}
>
<option value="BEGINNER">beginner</option>
<option value="INTERMEDIATE">intermediate</option>
<option value="EXPERT">expert</option>
</select>
2
Answers
I think that is related to how
setState
works in react.js.setState
is an async operation but it does not return a Promise, so you cannot useawait
orthen
setState
will cause your component rerendering and when your component rerenders, you will have the updated state value. However, for the performance reason, react decides when to rerender the component.when you called
console.log(form.ethExperienceLevel)
your component has not been rerendered. if you runconsole.log("chekcing the update",form.ethExperienceLevel)
outside the function, last console will be the updated the value.What happens is that
setForm
is executed asynchronously by React, so it is not guaranteed to be executed immediately after you call it, to be notified the exact moment when React executesetForm
(and therefore the value ofform
changes) you will have to watch for the changes inform
, so we need to useuseEffect
: