Home > Mobile >  React onChange doesn't return updated value after updating the state
React onChange doesn't return updated value after updating the state

Time:12-15

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} />

Console logs outdated data

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.

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:

  1. 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 
  1. 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
  • Related