T
TanStack•11mo ago
flat-fuchsia

Updates from a mutation in combination with a slow server

At a project I am working on, we are using the 'updates from mutation' strategy: https://tanstack.com/query/latest/docs/framework/react/guides/updates-from-mutation-responses. Basically we have kind of a wizard flow (multiple steps) and on each user interaction an auto-save should happen. This is how our mutation looks like:
const useUpdateWizard = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: ({ id, ...rest }: UpdateOptions) =>
service.updateWizard(id, rest),
onSuccess: (updatedWizard) => {
queryClient.setQueryData(
queryKeys.wizard(updatedWizard.id),
updatedWizard,
);
},
});
};
const useUpdateWizard = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: ({ id, ...rest }: UpdateOptions) =>
service.updateWizard(id, rest),
onSuccess: (updatedWizard) => {
queryClient.setQueryData(
queryKeys.wizard(updatedWizard.id),
updatedWizard,
);
},
});
};
As you can probably tell from the mutation above, it's a single endpoint in the backend which we need to call to update, passing the entire structure, looking similar to this:
{
"steps": {
"1": {
...
"countries": []
},
"2": {
...
},
"3": {
...
}
}
}
{
"steps": {
"1": {
...
"countries": []
},
"2": {
...
},
"3": {
...
}
}
}
In step 1 the user is able to select countries using checkboxes. I wondered what would happen if for example the server takes multiple seconds to persist my change (PUT) and the user selects another country within that same time frame: 1. Selected countries are shown based on the data retrieved by the useQuery 2. User clicks on "Spain" (NOTE that this will not select the checkbox yet!) 3. useUpdateWizard > mutate is triggered (takes 5 seconds, simulated this locally using a mocking server) 4. User selects "Belgium", still within those 5 seconds mentioned above 5. useUpdateWizard is triggered once again (also taking 5 seconds) 6. useUpdateWizard > onSuccess is triggered (for Spain), updating the data using setQueryData 7. The checkbox from step 2 (Spain) is now selected 8. useUpdateWizard > onSuccess is triggered (for Belgium), updating the data using setQueryData 7. The checkbox from step 4 (Belgium) is now selected BUT the one from step 2 (Spain) is now deselected
3 Replies
flat-fuchsia
flat-fuchsiaOP•11mo ago
I understand why Spain is not seleced anymore, as it was not part of the initial payload of the mutate in step 4 but I wonder how others work around these kind of 'issues'. I know I could show some loading indicator preventing the user from selecting other stuff but I would also like to get other opinions 🙂 Could another solution be creating individual backend endpoints? For example, instead of updating the entire object at once, creating an endpoint which allows to select a specific country?
extended-yellow
extended-yellow•10mo ago
There is a isPending field you gain access to when you submit the form. you could possibly disable everything while it loads(I'm not sure if this triggers an API request or something when you submit to the next step of the wizard). I would personally stick to a single endpoint, and just update the current state of your form to the next step. I hope this helps and pushes you in the right direction
flat-fuchsia
flat-fuchsiaOP•10mo ago
I am aware of the isPending field, that's what I mean by 'a loading indicator preventing the user from selecting other stuff'. The 'issue' is that the user is never actually submitting any form. I am triggering the update mutation on every user interaction. For example under the checkboxes is a dropdown, that dropdown is also triggering the mutation on selection change. I am aware that within a wizard this logic seems weird and I even discussed it with the business but that's what they want, maintaining all state, so when u user refreshes, everything is still there.

Did you find this page helpful?