I'm new to react native and am trying to create onboarding for my app, this is a simplified version. To stop the user from half answering my onboarding questions and allowing them to mess up the user data, I have a tempUserData
that the changes are made to which will finally be committed to the userData
once they finish a section.
The problem is that when I call setTempUserData
(last question for a section answered) and then call commitUserData
to commit the data, an old version of tempUserData
is committed to the UserData
.
My thought is that this may have to do with a sort of race condition, but I can't figure out the best way to go about fixing this issue and maybe somehow synchronizing the updates, or if my strategy of doing onboarding isn't ideal. Thanks for helping.
const [tempUserData, setTempUserData] = useState({ name: '', age: '' });
const [userData, setUserData] = useState({ name: '', age: '' });
// Function to update temp user data
const updateTempUserData = (newData) => {
setTempUserData((prevTempUserData) => ({
...prevTempUserData,
...newData,
}));
};
// Function to commit temp user data to actual user data
const commitUserData = () => {
setUserData((prevUserData) => ({
...prevUserData,
...tempUserData,
}));
};
I want the userData
to reflect the last state of the tempUserData
but I can't figure out if this is a natural way of using react or if there's a better way of going about this.
The change to tempUserData
is only visible when the GUI re-renders. You can only ever see state
updates when Reactjs re-renders the GUI and it usually batches this GUI re-render and doesn’t do this on the fly for performance reasons so in the meantime, all you will see is the stale value of tempUserData
until the next re-render occurs. [1]
You are better off keeping a separate simple Javascript object that you will use for other computation while you leave state
alone for only GUI rendering. The only problem is that state
will persist through multiple GUI re-renders while the Javascript object won’t be preserved each time a GUI re-render occurs.
The better alternative is to use references to values. References that will persist through out GUI re-renders. These references will be preserved. I’m talking about useRef
but of course Reactjs does not track mutations to such references so if you want to keep displaying state
updates to users, you certainly have to use state
that Reactjs will track and will re-render the GUI with when they change so that the change can be reflected in the GUI.
Here is one solution:
const data = { name: '', age: '' }
const [tempUserData, setTempUserData] = useState(data)
const { current: tempUserDataRef } = useRef(data)
const [userData, setUserData] = useState(data)
const updateTempUserData = (newData) => {
setTempUserData(prevTempUserData => ({
...prevTempUserData,
...newData
}))
tempUserDataRef = {
...tempUserDataRef,
...newData
}
}
const commitUserData = () => {
setUserData(prevUserData => ({
...prevUserData,
...tempUserDataRef
}))
}
[1] Reactjs does more than re-render the GUI.