Skip to content

queryClient not available in beforeLoad on client side loading #2593

Description

@hahnrobert

Which project does this relate to?

Router

Describe the bug

Following the Tanstack start + query example from the official page the following beforeLoad function successfully runs when I open the URL directly in a new browser tab, but fails, when I navigate to the URL by clicking a button on the website. This also fails in loader FWI

The difference is obviously server vs. client side loading.
Server-side loading succeeds and it can be observed through server side console logs that the queryClient is indeed set.
Client-side loading fails due to the following error:

context.queryClient.ensureQueryData is not a function
chunk-YPUWNOAE.js?v=91255f7a:3299 Uncaught TypeError: context.queryClient.ensureQueryData is not a function
    at Object.beforeLoad (events.$eventId._event.tsx:12:31)
    at chunk-YPUWNOAE.js?v=91255f7a:1953:113

Route Code:

import { createFileRoute, Outlet } from '@tanstack/react-router'
import { api } from '@/lib/api/api'

export const Route = createFileRoute('/_app/app/events/$eventId/_event')({
  beforeLoad: async ({ context, params }) => {
    // The following request fails
    const event = await context.queryClient.ensureQueryData({
      queryKey: ['event', params.eventId],
      queryFn: () => api.events.events.get({ eventId: params.eventId }),
    })
    return { ...context, event }
  },
  component: EventLayout,
})

function EventLayout() {
  return <Outlet />
}

Note: Accessing the queryClient using the corresponding useQueryClient() hook within the Component works without any issues.

For debugging sake here is the rest of my setup:

// router.tsx
import { DefaultCatchBoundary } from '@/components/DefaultCatchBoundary'
import { NotFound } from '@/components/NotFound'
import { QueryClient } from '@tanstack/react-query'
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
import { routerWithQueryClient } from '@tanstack/react-router-with-query'
import { routeTree } from './routeTree.gen'


export function createRouter() {
    const queryClient = new QueryClient()
    return routerWithQueryClient(createTanStackRouter({
        routeTree,
        defaultPreload: 'intent',
        context: { queryClient },
        defaultErrorComponent: DefaultCatchBoundary,
        defaultNotFoundComponent: () => <NotFound />,
    }), queryClient)
}

declare module '@tanstack/react-router' {
    interface Register {
        router: ReturnType<typeof createRouter>
    }
}
// client.tsx
import { StartClient } from '@tanstack/start'
import { hydrateRoot } from 'react-dom/client'
import { createRouter } from './router'

const router = createRouter()

hydrateRoot(document.getElementById('root')!, (
    <StartClient router={router} />
))
// __root.tsx
import { QueryClient } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { createRootRouteWithContext, Outlet, ScrollRestoration } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
import { Body, Head, Html, Meta, Scripts } from '@tanstack/start'
import * as React from 'react'
import appCss from './global.css?url'

export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
    meta: () => [
        {
            charSet: 'utf-8',
        },
        {
            name: 'viewport',
            content: 'width=device-width, initial-scale=1',
        },
    ],
    links: () => [
        { rel: 'stylesheet', href: appCss },
    ],
    component: RootComponent,
})

function RootComponent() {
    return (
        <RootDocument>
            <Outlet />
        </RootDocument>
    )
}

function RootDocument({ children }: { children: React.ReactNode }) {
    return (
            <Html>
                <Head>
                    <Meta />
                </Head>
                <Body>
                    {children}
                    <ScrollRestoration />
                    <Scripts />
                    <TanStackRouterDevtools position="bottom-right" />
                    <ReactQueryDevtools buttonPosition="bottom-right" />
                    <Toaster />
                </Body>
            </Html>
    )
}

Your Example Website or App

N/A

Steps to Reproduce the Bug or Issue

See above

Expected behavior

Independent whether the load is client- or server-side, it should succeed.

Screenshots or Videos

No response

Platform

  • OS: [e.g. macOS, Windows, Linux]
  • Browser: [e.g. Chrome, Safari, Firefox]
  • Version: [e.g. 91.1]

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions