T
TanStack7mo ago
plain-purple

`HydrationBoundary` won't pass **some** data

in my query config i have several keys
export const queryKeys = {
cookies: ['cookies'],
entity: (id: string | undefined) => ['entity', id],
period: (id: string | undefined) => ['period', id],
//
groupSchedule: (groupId: string, periodId: string) => ['schedules', 'group', groupId, 'period', periodId],
tutorSchedules: (tutorId: string, periodId: string) => ['schedules', 'tutor', tutorId, 'period', periodId],
tutors: ['tutors'],
groups: ['groups'],
periods: ['periods'],
} as const
export const queryKeys = {
cookies: ['cookies'],
entity: (id: string | undefined) => ['entity', id],
period: (id: string | undefined) => ['period', id],
//
groupSchedule: (groupId: string, periodId: string) => ['schedules', 'group', groupId, 'period', periodId],
tutorSchedules: (tutorId: string, periodId: string) => ['schedules', 'tutor', tutorId, 'period', periodId],
tutors: ['tutors'],
groups: ['groups'],
periods: ['periods'],
} as const
the issue part is cookies - for some reason it is populated on the server but not present on the client, making client components refetch it (see the video)
3 Replies
plain-purple
plain-purpleOP7mo ago
page does the prefetchQuery
export default async function HomePage() {
await queryNecessaryData() // here cookies are queried using nextjs cookie server function
const cookies = qc.getQueryData(serverCookiesQueryOptions.queryKey)!
console.log(cookies) // {periodId: 'xxx', entityId: 'xxx'} ✅

// pink thing supposed to display `periodId` cookie
return <SchedulePreview />
export default async function HomePage() {
await queryNecessaryData() // here cookies are queried using nextjs cookie server function
const cookies = qc.getQueryData(serverCookiesQueryOptions.queryKey)!
console.log(cookies) // {periodId: 'xxx', entityId: 'xxx'} ✅

// pink thing supposed to display `periodId` cookie
return <SchedulePreview />
SchedulePreview
export default function SchedulePreview({ ...attrs }: ComponentProps<'article'> & {}) {
// and here it does the refetch bcs the value is not present for some reason, leaving me with a flicker
const cookieQuery = useQuery(serverCookiesQueryOptions)

return (
<article>
<p>{cookieQuery?.data?.periodId}</p>
</article>
)
}
export default function SchedulePreview({ ...attrs }: ComponentProps<'article'> & {}) {
// and here it does the refetch bcs the value is not present for some reason, leaving me with a flicker
const cookieQuery = useQuery(serverCookiesQueryOptions)

return (
<article>
<p>{cookieQuery?.data?.periodId}</p>
</article>
)
}
in the title i said some data bcs cookie part is the only data not being hydrated here's how i get all the stuff
export async function queryNecessaryData() {
await Promise.all([
// cookies
qc.prefetchQuery(serverCookiesQueryOptions),
qc.prefetchQuery(groupsQueryOptions),
qc.prefetchQuery(tutorsQueryOptions),
qc.prefetchQuery(periodsQueryOptions),
])
const cookies = qc.getQueryData(serverCookiesQueryOptions.queryKey)!
// always present here
const entityId = cookies.entityId
const periodId = cookies.periodId
let promises = []
if (entityId) {
promises.push(qc.prefetchQuery(entityQueryOptions(entityId)))
}
if (periodId) {
promises.push(qc.prefetchQuery(periodQueryOptions(periodId)))
}
if (promises.length) {
await Promise.all(promises)
}
}
export async function queryNecessaryData() {
await Promise.all([
// cookies
qc.prefetchQuery(serverCookiesQueryOptions),
qc.prefetchQuery(groupsQueryOptions),
qc.prefetchQuery(tutorsQueryOptions),
qc.prefetchQuery(periodsQueryOptions),
])
const cookies = qc.getQueryData(serverCookiesQueryOptions.queryKey)!
// always present here
const entityId = cookies.entityId
const periodId = cookies.periodId
let promises = []
if (entityId) {
promises.push(qc.prefetchQuery(entityQueryOptions(entityId)))
}
if (periodId) {
promises.push(qc.prefetchQuery(periodQueryOptions(periodId)))
}
if (promises.length) {
await Promise.all(promises)
}
}
serverCookiesQueryOptions is this
export const serverCookiesQueryOptions = queryOptions({
queryKey: queryKeys.cookies,
queryFn: readCookies,
})
export const serverCookiesQueryOptions = queryOptions({
queryKey: queryKeys.cookies,
queryFn: readCookies,
})
readCookies is this
export async function readCookies() {
const handler = await serverCookiesHandler()
return {
entityId: handler.get('entityId'),
periodId: handler.get('periodId'),
} satisfies Partial<Cookies>
}

export async function serverCookiesHandler() {
// i renamed nextjs cookies() fn for convenience here
const sc = await serverCookies()
return {
get(cookie: Cookie) {
return sc.get(cookie)?.value
},
set(cookie: Cookie, value: string) {
return sc.set(cookie, value)
},
delete(cookie: Cookie) {
return sc.delete(cookie)
},
}
}
export async function readCookies() {
const handler = await serverCookiesHandler()
return {
entityId: handler.get('entityId'),
periodId: handler.get('periodId'),
} satisfies Partial<Cookies>
}

export async function serverCookiesHandler() {
// i renamed nextjs cookies() fn for convenience here
const sc = await serverCookies()
return {
get(cookie: Cookie) {
return sc.get(cookie)?.value
},
set(cookie: Cookie, value: string) {
return sc.set(cookie, value)
},
delete(cookie: Cookie) {
return sc.delete(cookie)
},
}
}
i just don't understand how come only ['cookies'] is getting refetched every time. It is present during the server render but client-side components do not care
plain-purple
plain-purpleOP7mo ago
UPDATE i partially fixed this issue (removed unnecessary refetch) by checking where the code runs - server or client and pick appropriate cookie api (nextjs api/browser api)
export const cookiesQueryOptions = queryOptions({
queryKey: queryKeys.cookies,
queryFn: isServer
? readCookies
: () => {
const cookies = getCookiesClient()
return {
entityId: cookies.get('entityId'),
periodId: cookies.get('periodId'),
} satisfies Partial<Cookies>
},
})
export const cookiesQueryOptions = queryOptions({
queryKey: queryKeys.cookies,
queryFn: isServer
? readCookies
: () => {
const cookies = getCookiesClient()
return {
entityId: cookies.get('entityId'),
periodId: cookies.get('periodId'),
} satisfies Partial<Cookies>
},
})
plain-purple
plain-purpleOP7mo ago
as you can see the blue indicator is not appearing anymore the flicker remains though

Did you find this page helpful?