I'm trying to achieve something like,
whenever the user change any input field value, update the state value normally and do something, like submit the form with updated state value.
I'm currently doing
const [data, setData] = useState({
search: '',
field: '',
direction: '',
})
const onHandleChange = (e) => {
setData({
...data,
[e.target.name]: e.target.value,
})
// Do soemthing with the updated data, for now I'll just console.log
console.log(data);
}
<input type="search" name="search" onChange={onHandleChange} value={data.search} />
As on the screenshot, if I type 123
the most recent console log would be 12
It's always 1 step behind :/
One thing I thoght of using a useEffect()
but useEffect
also runs the first render, which I dont want. I wouldn't want the form gets submitted on first render, but only when the user changes anything.
CodePudding user response:
Well as Sanket Shas said, "React does not guarantee that the state changes are applied immediately".
So, you can try something like this if you don't want to use useEffect:
const [data, setData] = useState({
search: "",
field: "",
direction: "",
});
const onHandleChange = (e) => {
let dataUpdated = {
...data,
[e.target.name]: e.target.value,
};
setData(dataUpdated);
// Do soemthing with the updated data, for now I'll just console.log
console.log(dataUpdated);
};
<input type="search" name="search" onChange={onHandleChange} value={data.search} />
CodePudding user response:
This is happening because React does not guarantee that the state changes are applied immediately. This makes reading state
right after updating(in your case setData
) a potential pitfall and can potentially return the existing value due to async nature.
- Calling
setState
only affects the next render and does not change state in the already running code
React Doc: https://reactjs.org/docs/react-component.html?#setstate
And regarding solution of your problem
a) You can use useEffect
by putting necessary fields as dependency array
and doing conditional check:
- If you've fixed number of fields:
useEffect(()=>{
if(data.search !== '' || data.field !== '' || data.direction !== ''){
// condition on which you want to update state
}
},[data]) // fields whose changes you want to monitor
- If you've more fields:
useEffect(()=>{
if(Object.values(data)?.some(value) => value){
// condition on which you want to update state
}
},[data]) // fields whose changes you want to monitor
b) If you don't want to use useEffect
you can try this:
const onHandleChange = (e) => {
let updatedData = {
...data,
[e.target.name]: e.target.value,
};
setData(updatedData);
console.log(updatedData); // here you'll get latest value
};
CodePudding user response:
you can try using this way to skip the initial useEffect call and use useEffect ,hope this helps
With useEffect, how can I skip applying an effect upon the initial render?
CodePudding user response:
you need to watch for data in useEffect as setstate is async action and will not reflect result immediatly,
useEffect(()=>{
// required action here
},[data]) // watch changes here