cugs
cugs
TtRPC
Created by cugs on 11/19/2023 in #❓-help
Multiple optimistic updates and old data from refetches
You've helped me understand the crux of the issue: cancel does not cancel refetches invoked via invalidate. This seems strange to me, but it's likely just due to my lack of familiarity/understanding of React Query, if I was to guess. I'm starting to believe this has more to do with me employing anti-patterns in my code rather than not understanding the library 😅 I might have to rethink my approach.
8 replies
TtRPC
Created by cugs on 11/19/2023 in #❓-help
Multiple optimistic updates and old data from refetches
Hey @ghard1314 thanks so much for your help!!! 🙂
When you call invalidate that triggers a refetch from the server which is going to override any optimistic updates you made to your cache like you are seeing.
Makes sense. But my thinking was that calling trpcContext.exercise.all.cancel(); would cancel any previous exercise.all.invalidate() invoked refetches, is this not the point of cancel?
do you really need to refetch data?
Good pickup. I don't need to, you're correct. For this example I only need to handle rolling back on error, and I will likely change this particular code to do nothing in the onSettled callback. But the reason I'm still wanting to get to understand this, is because I'm using this pattern in a few places, and some of these use-cases do need to make use of the onSettled callback in this way.
8 replies
TtRPC
Created by cugs on 11/19/2023 in #❓-help
Multiple optimistic updates and old data from refetches
These are the relevant bits of code:
const { isFetching: fetchingExercises, data: exercises = [] } =
trpc.exercise.all.useQuery(
{ workoutId: workoutId },
{
onSettled: () => {
console.log("refetch");
},
enabled: !!workoutId.length,
},
);

const deleteExercise = trpc.exercise.delete.useMutation({
onMutate: async (variables) => {
console.log("onMutate");
await trpcContext.exercise.all.cancel();
const previousExercises =
trpcContext.exercise.all.getData({ workoutId: workoutId }) || [];
trpcContext.exercise.all.setData(
{ workoutId: workoutId },
previousExercises.filter(
(exercise) => exercise.id !== variables.exerciseId,
),
);
return { previousExercises };
},
onError(_, __, context) {
if (context?.previousExercises) {
trpcContext.exercise.all.setData(
{ workoutId: workoutId },
context.previousExercises,
);
}
},
async onSettled() {
console.log("onSettled");
await trpcContext.exercise.all.cancel(); // This call is not actually necessary afaik, just ruling things out...
trpcContext.exercise.all.invalidate({ workoutId: workoutId });
},
});
const { isFetching: fetchingExercises, data: exercises = [] } =
trpc.exercise.all.useQuery(
{ workoutId: workoutId },
{
onSettled: () => {
console.log("refetch");
},
enabled: !!workoutId.length,
},
);

const deleteExercise = trpc.exercise.delete.useMutation({
onMutate: async (variables) => {
console.log("onMutate");
await trpcContext.exercise.all.cancel();
const previousExercises =
trpcContext.exercise.all.getData({ workoutId: workoutId }) || [];
trpcContext.exercise.all.setData(
{ workoutId: workoutId },
previousExercises.filter(
(exercise) => exercise.id !== variables.exerciseId,
),
);
return { previousExercises };
},
onError(_, __, context) {
if (context?.previousExercises) {
trpcContext.exercise.all.setData(
{ workoutId: workoutId },
context.previousExercises,
);
}
},
async onSettled() {
console.log("onSettled");
await trpcContext.exercise.all.cancel(); // This call is not actually necessary afaik, just ruling things out...
trpcContext.exercise.all.invalidate({ workoutId: workoutId });
},
});
8 replies