0

I have created a state to store all of my filters, however, the state is not changing properly even though I have used setFilter() on it. The state only changes after I select something else. This is where I initialize the state:

    const [filter, setFilter] = useState({
        a: 'ALL',
        b: 12,
    });

Here is the place where I filter everything:

    const parseA = (e) => {
        console.log('before', filter);
        setFilter(prevValues => {
            console.log('returning setFilter', {
                ...prevValues,
                a: Number(e.target.value)
            });
            return {
                ...prevValues,
                a: Number(e.target.value)
            }
        })
        console.log('after', filter);
    }

In my case, I am using an HTML form for the user to change the state.

                            <select value={filter['a']} onChange={parseA}>
                                <option onSelect={parseA}>8</option>
                                <option id="10">10</option>
                                <option id="12">12</option>
                                <option id="14">14</option>
                            </select>

After the user selects something, the state should change to what the user selected. However, it is not changing in the right way. The first time the user selects something, the state stays the same as before. The second time the user selects something, the state is now what the user previously selected.

Using the logs I have from above, I can see that the "returning setFilter" log is correct. However, both the "before" and "after" are the exact same!

  • 1
    useState is async. You will not see change until next render cycle. https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately – Tushar Shahi Jul 05 '21 at 18:27
  • 2
    Does this answer your question? [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – Tushar Shahi Jul 05 '21 at 18:27

2 Answers2

0

setState actions are asynchronous. So you can not see the right result after calling setFilter function. If you want to get the right result after calling setFilter, you should use use-state-with-callback library.

Please take a look at the docs.(https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous)

lovejet
  • 9
  • 3
0

As Tushar Shahi wrote, setting state is asynchronous. The last console.log() there is logging the filter that's trapped in the closure, so it can't possibly reflect the change.

   const parseA = (e) => {
        console.log('before', filter);
        setFilter(prevValues => {
            console.log('returning setFilter', {
                ...prevValues,
                a: Number(e.target.value)
            });
            return {
                ...prevValues,
                a: Number(e.target.value)
            }
        })
        console.log('after', filter);
    }

To wait for the state to change and act on the change, use useEffect():

useEffect(() => {

    console.log(`filter now =`, filter);

}, [filter]); //this runs once after every change to `filter`
Neal Burns
  • 839
  • 4
  • 5