Skip to content

Using toPromise in a tanstack router loader loses internal queryRef #12619

Closed as not planned
@jeremyoverman

Description

@jeremyoverman

Issue Description

When using a preload query from createQueryPreloader in a tanstack router loader method and .toPromise(), the resolved queryRef is lost when navigating between routes, but not on refresh.

For example, given this apollo setup:

import { ApolloClient, createQueryPreloader, InMemoryCache } from "@apollo/client";

export const apollo = new ApolloClient({
  uri: "https://rickandmortyapi.com/graphql",
  cache: new InMemoryCache(),
});

export const preloadQuery = createQueryPreloader(apollo);

And this route:

import { graphql } from '@/gql'
import { preloadQuery } from '@/utils/graphql'
import { useReadQuery } from '@apollo/client'
import { createFileRoute, useLoaderData } from '@tanstack/react-router'

const GetRickDocument = graphql(`
  query GetRick {
    characters(page: 1, filter: { name: "Rick" }) {
      results {
        id
        name
      }
    }
  }
`)

export const Route = createFileRoute('/rick')({
  component: RouteComponent,
  loader: async () => {
    // If I don't use toPromise, it works as expected but the query doesn't block
    // the loader.
    //
    // const queryRef = preloadQuery(GetRickDocument);

    const queryRef = await preloadQuery(GetRickDocument).toPromise();
    
    // Looks correct even when navigating pages
    console.log('queryRef from loader', queryRef);
    
    return queryRef;
  }
})

function RouteComponent() {
  const queryRef = useLoaderData({ from: Route.id })

  // Missing internal refs when navigating pages (but not on refresh)
  console.log('queryRef from component', queryRef)

  const { data: { characters }} = useReadQuery(queryRef);

  return (
    <div>
      <h1>Ricks</h1>
      <ul>
        {characters?.results?.map(character => (
          <li key={character?.id}>{character?.name}</li>
        ))}
      </ul>
    </div>
  )
}

When navigating directly to http://localhost:3000/rick, or refreshing the page, the page loads as expected. However, when navigating to the page via a link, I get the error:

Expected a QueryRef object, but got something else instead.

Logging out the queryRef from the loader shows the expected output:

queryRef from loader {Symbol(apollo.internal.queryRef): InternalQueryReference2, Symbol(apollo.internal.refPromise): Promise, toPromise: ƒ}

However the queryRef in the component seems to lose it's internal reference:


rick.tsx:38 queryRef from component {Symbol(apollo.internal.queryRef): InternalQueryReference2, Symbol(apollo.internal.refPromise): Promise, toPromise: ƒ}
rick.tsx:38 queryRef from component {Symbol(apollo.internal.queryRef): InternalQueryReference2, Symbol(apollo.internal.refPromise): Promise, toPromise: ƒ}
rick.tsx:38 queryRef from component {toPromise: ƒ}
rick.tsx:38 queryRef from component {toPromise: ƒ}

Link to Reproduction

https://github.com/jeremyoverman/apollo-loader-demo

Reproduction Steps

  1. Clone the reproduction repo
  2. npm install
  3. npm run dev
  4. Navigate to either Rick or Morty
  5. Notice the Expected a QueryRef object, but got something else instead. error
  6. Check the console to see the incorrect value of queryRef from component
  7. Refresh the page, notice it loads as expected

@apollo/client version

3.13.8

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions