#casdading tanstack queries in beforeLoad + loader + usage in RouteComponent

12 messages · Page 1 of 1 (latest)

clever steppe
#

I was told a few months ago by @charred wing that a good pattern to use tanstack-query with tanstack-router was:

export const Route = createFileRoute('/')({
  component: RouteComponent,
  // ---
  beforeLoad: ({ context: { trpc }, search }) => ({
    queryOptions: trpc.route.handler.queryOptions(search)
  }),
  loader: ({ context: { queryClient, queryOptions } }) =>
    queryClient.prefetchQuery(queryOptions)
})

function RouteComponent() {
  const { queryOptions } = Route.useRouteContext()
  const { data } = useSuspenseQuery(queryOptions)
}

which indeed, is an ok pattern. a bit verbose imho but does cover preloading from the router while maintaining access to subscriptions, etc etc.

now... this does not play well if you need to make cascading queries ; so how would i handle to write queryOptions once with cascading queries?

#

with something like this (conceptually):

export const Route = createFileRoute('/')({
  component: RouteComponent,
  // ---
  loaderDeps: ({ search }) => search,
  loader: async ({ context: { queryClient, queryOptions, trpc }, deps }) => {
  }
    const object1 = await queryClient.ensureQueryData(
      trpc.route.handler.queryOptions(search)
    )

    if (object1.object2Id) {
      await queryClient.prefechQuery(
        trpc.route.otherHandler.queryOptions({ id: object1.object2Id })
      )
    }
})

function RouteComponent() {
  const { queryOptions } = Route.useRouteContext()
  const { data } = useSuspenseQueries( ??? )
}

would that mean i must use Route.useLoaderData() to return the queryOptions?

#

if so, i really wonder why bother with beforeLoad if that's the case. wouldn't it be easier to conceptually do only this:

export const Route = createFileRoute('/')({
  component: RouteComponent,
  // ---
  loaderDeps: ({ search }) => search,
  loader: async ({ context: { queryClient, queryOptions }, deps }) => {
  const queryOptions = trpc.route.handler.queryOptions(search)
  await queryClient.prefetchQuery(queryOptions)

  return { queryOptions }
  }
    
})

function RouteComponent() {
  const { queryOptions } = Route.useLoaderData()
  const { data } = useSuspenseQuery(queryOptions)
}

that would scale to cascading queries much more easily, no?

clever steppe
#

could i get advice 🙏 hate to mention but please <@&1156977987980361828>

charred wing
#

you can make beforeLoad return a function

#

so I'd say:

  beforeLoad: ({ context: { trpc }, search }) => ({
    queryOptions1: trpc.route.handler.queryOptions(search),
    queryOptions2: (id)  => trpc.route.otherHandler.queryOptions({ id })
  }),
gloomy relic
#

@junior cedar I experienced another use case recently for our additiona lifecycle methods 👆

amber pewter
clever steppe
#

@charred wing i'm still puzzled as for why going further into the use of beforeLoad is better than leverage the loader, giving that the loader api can achieve the same with less code written.

charred wing
#

It doesn't make much difference now but what you'd really want is our new onMatch lifecycle method that doesn't exist yet and the migration from beforeLoad is simpler

amber pewter
charred wing