MitchEff
MitchEff

Reputation: 1557

React hooks update sort of whenever they feel like it

So, I'm using hooks to manage the state of a set of forms, set up like so:

    const [fieldValues, setFieldValues] = useState({}) // Nothing, at first

When setting the value, the state doesn't update:

    const handleSetValues = values => {
        const _fieldValues = {
            ...fieldValues,
            ...values
        }

        setFieldValues(_fieldValues)

        console.log(fieldValues) // these won't be updated

        setTimeout(() => {
            console.log(fieldValues) // after ten seconds, it's still not updated
        },10000)
    }

If I call the function a second time, it'll have updated, but that's not gonna work for me. I never saw behaviour like this in class components.

Is it meant to... like, not update? Or just update whenever it feels like it? Really confusing behaviour.

Upvotes: 0

Views: 372

Answers (2)

Zain Ul Abideen
Zain Ul Abideen

Reputation: 1602

setFieldValues(_fieldValues) is an async call, means you won't able to get the result in the very next line of this.

You can use useEffect hook.

useEffect(() => {
    // do your work here
  }, [fieldValues]);

It seems from your question that you have background of Class components of React, so useEffect is similar to componentDidMount and componentDidUpdate lifecycle methods.

useEffect calls whenever the state in the dependency array (in your case [fieldValues]) changes and you get the updated value in useEffect body.

You can also perform componentWillUnmount work in useEffect as well.

Have a brief guide.

Upvotes: 2

Agney
Agney

Reputation: 19194

setFieldValues is an asynchronous function, so logging the value below the statement will not have any effect.

Regarding using setTimeout, the function would capture the current value of props being passed to it and hence that would be the value printed to the console. This is true to any JS function, see the snippet below:

function init(val) {
  setTimeout(() => {
      console.log(val);
  }, 1000);
}

let counterVal = 1;

init(counterVal);
counterVal++;

So how can we print the values when the value changes? The easy mechanism is to use a useEffect:

useEffect(() => {
  console.log(fieldValues)
}, [fieldValues]);

Upvotes: 0

Related Questions