TanStackT
TanStack2mo ago
11 replies
hidden-sapphire

Best practice for using loader data + tanstack query together?

Wondering if it's generally not recommended to make use of useLoaderData() for data that is also managed via tanstack query?

I have the following scenario where I want a route to have access to a piece of information that is guaranteed to exist. I don't need this information to be reactive so I figured deriving it via the loader would be suitable:

// In defineFileRoute()
loader: async ({ context }) => {
  const info = context.queryClient.ensureQueryData(infoQueryOptions)

  if (!info.name) {
    // Name doesn't exist so we redirect
    throw redirect(...)
  }

  return { name: info.name }
}

// In component
function RouteComponent() {
  const { name } = Route.useLoaderData()
}


However, this seems to result in an issue in the following sequence:

1. Navigate away from route
2. Do something that updates the name and invalidates the infoQueryOptions
3. Return to route

In (3), the name is still showing the old name, not the one in (2). However, if I leave and return to the route once again, it gets updated appropriately.

Is this generally expected behavior? Very likely that I've missed something in the documentation.

So instead of the approach above, I opted for fully relying on query, which I've noticed tends to be the recommendation and works as expected:

// In defineFileRoute()
loader: async ({ context }) => {
  const info = context.queryClient.ensureQueryData(infoQueryOptions)

  if (!info.name) {
    // Name doesn't exist so we redirect
    throw redirect(...)
  }
}

// In component
function RouteComponent() {
  const { data } = useSuspenseQuery(infoQueryOptions)

  if (!data.name) {
    // Redirect in render body
    return <Navigate />
  } 
}


I wasn't sure if the usage of <Navigate /> in the render body is similar to throwing a redirect in the loader, so I was initially hesitant to use this. This seemed to be the only way to make it such that the name is guaranteed for the rest of the component to use though.
Was this page helpful?