T
TanStack•2mo ago
national-gold

Is it possible to access browser QueryClient without passing it as a function parameter?

I couldn't seem to find a quick answer, but I have a beforeLoad that I'd like to call to verify permissions and since I'm use Tanstack Query I want to use ensureQueryData so I can utilize browser cache if it exists. I would like to extract the logic in to a function and I was curious if I could access my client without needing to pass it as a function parameter?
const hasPermission = async (queryClient: QueryClient, permission: PermissionEnum) => {
// implementation...

await queryClient.ensureQueryData(...)
}

export const Route = createFileRoute("/workspace")({
beforeLoad: async ({ context, params }) => {

// i would like to avoid this
await hasPermission(context.queryClient, "contact-list.read")
},
component: RouteComponent,
})
const hasPermission = async (queryClient: QueryClient, permission: PermissionEnum) => {
// implementation...

await queryClient.ensureQueryData(...)
}

export const Route = createFileRoute("/workspace")({
beforeLoad: async ({ context, params }) => {

// i would like to avoid this
await hasPermission(context.queryClient, "contact-list.read")
},
component: RouteComponent,
})
I know I could put this function in my context but I guess I'm just asking conceptually how to access the browser QueryClient outside react land? In nextjs, tanstack query has a getQueryClient you could export https://tanstack.com/query/latest/docs/framework/react/guides/advanced-ssr#initial-setup to ensure you were grabbing the same query client on the browser but a new instance on each server request. Is it okay to do something similar like the below so i can just import getQueryClient in my client side functions?
let browserQueryClient: QueryClient | undefined = undefined

export function getQueryClient() {
if (typeof window === "undefined") {
return new QueryClient()
} else {
if (!browserQueryClient) browserQueryClient = new QueryClient()
return browserQueryClient
}
}

export function getRouter() {
const queryClient = getQueryClient()

const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: "intent",
scrollRestoration: true,
})

setupRouterSsrQueryIntegration({
router,
queryClient,
})

return router
}
let browserQueryClient: QueryClient | undefined = undefined

export function getQueryClient() {
if (typeof window === "undefined") {
return new QueryClient()
} else {
if (!browserQueryClient) browserQueryClient = new QueryClient()
return browserQueryClient
}
}

export function getRouter() {
const queryClient = getQueryClient()

const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: "intent",
scrollRestoration: true,
})

setupRouterSsrQueryIntegration({
router,
queryClient,
})

return router
}
Thanks a lot!
Advanced Server Rendering | TanStack Query React Docs
Welcome to the Advanced Server Rendering guide, where you will learn all about using React Query with streaming, Server Components and the Next.js app router. You might want to read the before this on...
3 Replies
national-gold
national-goldOP•2mo ago
wait a minute...since I'm using tanstack start, I can probably get away with creating this
let browserQueryClient: QueryClient | undefined = undefined

export const getQueryClient = createIsomorphicFn()
.server(() => {
return new QueryClient()
})
.client(() => {
if (!browserQueryClient) browserQueryClient = new QueryClient()
return browserQueryClient
})
let browserQueryClient: QueryClient | undefined = undefined

export const getQueryClient = createIsomorphicFn()
.server(() => {
return new QueryClient()
})
.client(() => {
if (!browserQueryClient) browserQueryClient = new QueryClient()
return browserQueryClient
})
in a lib/react-query.ts importing it for use in createRouter and then importing it in any file i need access to the router 🤔 is that correct?
magic-beige
magic-beige•2mo ago
But then the router and your hasPermission will have different query client instances in the server The query data will not be streamed then
national-gold
national-goldOP•2mo ago
hmm so you got me to dig in a bit and i'm not quite sure that's the case, for example I'm using
setupRouterSsrQueryIntegration({
router,
queryClient: context.queryClient,
})
setupRouterSsrQueryIntegration({
router,
queryClient: context.queryClient,
})
and according to this implementation, if I understand correctly.... https://github.com/TanStack/router/blob/91d994046a2add5bdc25cea91092634b615fdeb8/packages/router-ssr-query-core/src/index.ts#L30 i believe it takes in the server query client -> dehydrates it, and then on the client it takes in whatever queryClient you pass, merges it with the dehydrated server query client and then hydrates it back I can confirm this by calling ensureQueryData on a beforeLoad and loader refresh the page to force this data to load on the server request and then when I useSuspenseQuery in my component, I don't see a fetch request in my network tab 🤔 thank you for your response by the way!
GitHub
router/packages/router-ssr-query-core/src/index.ts at 91d994046a2ad...
🤖 A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more). - TanStack/router

Did you find this page helpful?