T
TanStack7mo ago
optimistic-gold

SSR set initialData for Tanstack Query (useQuery) isn't working

Am I doing something wrong because useQuery initialData on server is not being set from route state data resulting in a flicker of UI / hydration errors. If I only use the state data all is good however I can't do optimistic updates via queryClient API used by useQuery/useMutation .
export const Route = createFileRoute('/')({
component: Home,
loader: async () => ({
jobs: (await getJobs()) ?? [],
}),
});

function Home() {
const router = useRouter();
const state = Route.useLoaderData();
const queryClient = useQueryClient();
const jobs = useQuery({
queryKey: ['jobs'],
queryFn: () => getJobs(),
initialData: state.jobs,
});

// On server side the initial data of query is false, client side logs are all true.
console.log('s first job enabled:', state.jobs.at(0)?.enabled); // true
console.log('q first job enabled:', jobs.data.at(0)?.enabled); // false
console.log('c first job enabled:', queryClient.getQueryData(['jobs'])?.at(0)?.enabled); // false

// also have mutations that does optimistic updates use query cache
const editJobFn = useMutation({
mutationFn: editJob,
onMutate: async (newJob) => {
await queryClient.cancelQueries({ queryKey: ['jobs', newJob.data.id] });
const previousJobs = queryClient.getQueryData(['jobs']);
queryClient.setQueryData(['jobs'], (jobs: Jobs) =>
jobs.map((j) => (j.id === newJob.data.id ? { ...j, ...newJob.data } : j)),
);
return { previousJobs };
},
onSettled: (job) => {
queryClient.invalidateQueries({ queryKey: ['jobs', job?.id] });
router.invalidate();
},
onError: (err, variables, context) => {
queryClient.setQueryData(['jobs'], context?.previousJobs);
},
});

...
}
export const Route = createFileRoute('/')({
component: Home,
loader: async () => ({
jobs: (await getJobs()) ?? [],
}),
});

function Home() {
const router = useRouter();
const state = Route.useLoaderData();
const queryClient = useQueryClient();
const jobs = useQuery({
queryKey: ['jobs'],
queryFn: () => getJobs(),
initialData: state.jobs,
});

// On server side the initial data of query is false, client side logs are all true.
console.log('s first job enabled:', state.jobs.at(0)?.enabled); // true
console.log('q first job enabled:', jobs.data.at(0)?.enabled); // false
console.log('c first job enabled:', queryClient.getQueryData(['jobs'])?.at(0)?.enabled); // false

// also have mutations that does optimistic updates use query cache
const editJobFn = useMutation({
mutationFn: editJob,
onMutate: async (newJob) => {
await queryClient.cancelQueries({ queryKey: ['jobs', newJob.data.id] });
const previousJobs = queryClient.getQueryData(['jobs']);
queryClient.setQueryData(['jobs'], (jobs: Jobs) =>
jobs.map((j) => (j.id === newJob.data.id ? { ...j, ...newJob.data } : j)),
);
return { previousJobs };
},
onSettled: (job) => {
queryClient.invalidateQueries({ queryKey: ['jobs', job?.id] });
router.invalidate();
},
onError: (err, variables, context) => {
queryClient.setQueryData(['jobs'], context?.previousJobs);
},
});

...
}
2 Replies
ambitious-aqua
ambitious-aqua7mo ago
StackBlitz
Router Start Basic React Query Example - StackBlitz
Run official live example code for Router Start Basic React Query, created by Tanstack on StackBlitz
optimistic-gold
optimistic-goldOP7mo ago
@jarvissa Oh nice, I see queryClient is passed in to createTanStackRouter and then accessed via context, I will look more at that repo. I did suspect I was maybe using tanstack query wrong. Thanks for quick response ❤️

Did you find this page helpful?