Invalidate Data Cache on Vercel
Unanswered
Tomistoma posted this in #help-forum
TomistomaOP
I'm trying to get fresh data whenever my data refetches after a mutation, but the UI isn't updating for my users or invalidating.
Client component data Fetch:
Client component data Fetch:
const { data: linkedProductView } = useQuery<LinkedProductView[]>({
queryKey: ['linkedProductView'],
queryFn: async () => {
const response = await fetch('/api/linkedProductView', {
cache: 'no-store',
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache'
}
});
// Force revalidation by adding timestamp
const data = await response.json();
return data;
},
staleTime: 0,
gcTime: 0,
refetchOnMount: true,
refetchOnWindowFocus: true,
refetchInterval: 5000,
});
6 Replies
TomistomaOP
For the UI update mutation we have an optimstic update and onSuccess we invalidate the from react query fetch:
const verifyMutation = useMutation({
mutationFn: verifyProductLink,
// Update UI before server responds
onMutate: async (linkId) => {
// Save old state for rollback
const previousData = queryClient.getQueryData(['linkedProductView']);
// Optimistically update UI
queryClient.setQueryData(['linkedProductView'], (old: LinkedProductView[] | undefined) =>
old?.map(item =>
item.linkId === linkId
? { ...item, isVerified: true }
: item
) || []
);
return { previousData };
},
// If server call fails, rollback UI
onError: (err, variables, context: { previousData: any } | undefined) => {
if (context) {
queryClient.setQueryData(['linkedProductView'], context.previousData);
}
toast({
variant: "destructive",
title: "Error",
description: "Failed to verify product",
});
},
// If successful, UI is already updated
onSuccess: () => {
// Invalidate and refetch to sync with other sessions
queryClient.invalidateQueries({ queryKey: ['linkedProductView'] });
toast({
title: "Success",
description: "Product verified successfully",
});
}
});
In the server action mutation itself we revalidate the path
'use server'
import { revalidatePath } from 'next/cache';
import { drizzle } from 'drizzle-orm/neon-http';
import { eq } from 'drizzle-orm';
import * as schema from '@/drizzle/amazon/migrations/schema';
import { neon } from "@neondatabase/serverless";
export async function verifyProductLink(linkId: number) {
try {
if (!process.env.NEON_DATABASE_URL) {
throw new Error('NEON_DATABASE_URL is not defined');
}
const sql = neon(process.env.NEON_DATABASE_URL);
const db = drizzle(sql, { schema });
await db.update(schema.amazonShopifyProductLinks)
.set({ isVerified: true })
.where(eq(schema.amazonShopifyProductLinks.id, linkId));
revalidatePath('/sku-sync', 'page');
return { success: true };
} catch (error) {
console.error('Failed to verify product link:', error);
return { success: false, error: (error as Error).message };
}
}
Least Storm-Petrel
Does it refetch every 5s with the new data after the mutation?
If yes, just try to trigger a refetch instead of an invalidate. The query should already be marked as stale because of the query's settings, I think.
(btw for code blocks you can add a language identifier, e.g. ts after the 3 ticks ```ts which makes it syntax highlight)
If yes, just try to trigger a refetch instead of an invalidate. The query should already be marked as stale because of the query's settings, I think.
(btw for code blocks you can add a language identifier, e.g. ts after the 3 ticks ```ts which makes it syntax highlight)
@Least Storm-Petrel Does it refetch every 5s with the new data after the mutation?
If yes, just try to trigger a refetch instead of an invalidate. The query should already be marked as stale because of the query's settings, I think.
(btw for code blocks you can add a language identifier, e.g. ts after the 3 ticks \`\`\`ts which makes it syntax highlight)
TomistomaOP
It does but I added logging to be able to see the cache hits or skips and I realized it was hitting cache each time and returning the stale data.
I added two lines to my server action which worked to skip the cache and then the refetch worked
Ill post actualy lines i added