gokul m
gokul m

Reputation: 21

why Changing ref value not working as expected inside setState callback?

Not able to access the current value of ref inside a setState callback but able to access the current value from the ref outside setState callback.

Reference:
Working Example

Not working example

Upvotes: 1

Views: 334

Answers (4)

Jehu Amanna
Jehu Amanna

Reputation: 46

There is perfectly nothing wrong with working and non-working solutions.

They are all behaving as expected.

One thing to know is that the callback function runs two times during development. (That's why the criteria for that callback function is to be pure).

In the nonworking example, the temp variable is inside the callback function. Hence in the first run, it fetches the value from the input, assigns it temp, and resets the input box to 0 and does not update the return array, And in the second run, it fetches the value from the input again which is empty and resets the input box to 0, and does update now the return array.

That's why you see an empty string appended to the list displayed.

Check out this react documention. https://beta.reactjs.org/learn/keeping-components-pure

Upvotes: 1

JohnMaher149
JohnMaher149

Reputation: 11

I'm not super sure if a callback function is necessary here in this case (might be wrong): I think you could just replace the function with this:

const onSubmit = (e) => {
    e.preventDefault();
    setData([...data, refObj.current.value]);
    refObj.current.value = "";
};

Just tested this in the codesandbox and it seems to work well

Upvotes: 0

Nick Parsons
Nick Parsons

Reputation: 50759

State updater functions should be pure. Your state updater function isn't pure, because if called multiple times with the same arguments (in this case there are none), it produces/returns different results:

const temp = refObj.current.value; // "x" on the first call, `""` on the second run
refObj.current.value = "";
return [...prev, temp]; // firstly returns `[...prev, x]`, then `[...prev, ""]` on the next call

Keeping your state updater function pure helps reduce things like state mutations and side effects. To help catch and allow you to detect unwanted side effects, React invokes certain functions twice (when in development and your component is wrapped in <StrictMode>), including your component as a whole, state initializer functions, and your state updater functions. Because React is invoking the above state setter function twice, you're going to be getting the emptied "" value you set on the second time round. React, however, does not invoke event listener functions twice (as these are ok to cause side-effects), so moving temp outside of the state updater function directly into onSubmit works as expected as refObj.current.value is only read once in that case.

Upvotes: 1

Arnau
Arnau

Reputation: 455

Don't forget that setting a State is asynchronous. You don't know exactly when it's called, therefore some of the values that you expect may not available or different, like in this case with the ref.

More info https://reactjs.org/docs/state-and-lifecycle.html

Upvotes: -1

Related Questions