Reputation: 21
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
Upvotes: 1
Views: 334
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
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
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
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