useReadQuery but for fragment/partial data?

Hello,
let’s say I have two routes: /items and /items/:id and a component <ItemCard/> with defined ItemCardFragment

My queries look like:

items() {
  ...ItemCardFragment  
}

and

item(id: $id) {
   ...ItemCardFragment

  someOtherProp1
  someOtherProp2
  someOtherProp3
  someOtherProp4
}

I use react-router and both pages preload those queries. Both pages also render , the difference is that details page also renders some additional component on the page

Question:

When I go to the details page I want to be immediately displayed since all the data is already in the cache and suspend rendering only for components that require someOtherPropN. How am I supposed to achieve this? Since queries requires different set of fields useReadQuery will suspend until all the data is fetched.
I think what I’m wishing for is something like useReadQuery(queryRef, {fragment: ItemCardFragment})

Workarounds:

I can think of a couple of workarounds:

  1. Split the query for the details page, e.g. itemCardProps: item() {...ItemCardFragment} and item() {someOtherPropN}. Then I can use useReadQuery for specific queryRef. The downside is that Apollo will make two network request when I go to that page by url. (maybe can be worked around with some batching technique?)
  2. Use useFragment for the part that uses ItemCard. Move useReadQuery under suspense somewhere along the tree. I’m currently using this approach

Thanks in advance for any tips :pray:

Hi @misha-erm!

That is currently still on our Roadmap. We are currently working on Data Masking, and as soon as that’s done we’ll get to the suspenseful useFragment story.

Both of your workarounds seem currently viable - you’ll have to decide for yourself, which tradeoffs work better for you.

1 Like

Nice to know that’s on the roadmap, thank you

After some tries what worked best for me was combination of returnPartialData: true in preloadQuery together with

const {data: {item}} = useReadQuery(queryRef)

const {data: dataFromFragment, complete} = useFragment(); 

if (!item) return <NotFound />

if(!complete) return null;

return <ItemCard item={dataFromFragment}  />
...

@lenz one more question though

Is it known that preloadQuery with returnPartialData: true doesn’t throw error? Failed to find any info about that in the docs

I believe any error handling should happen in the component where you call readQuery - are you also not seeing that?

Don’t see that. I blocked the query in my devtools but useReadQuery never throws and just returns empty object

The preloader looks like this:

const TournamentQuery = gql(`
query TournamentQuery($id: ID!) {
  tournament(id: $id) {
    ...TournamentBannerFragment
    ...TournamentMySubmissionsFragment
    ...TournamentOverviewFragment
    ...TournamentAwardsFragment
  }
}
`);


export const tournamentLoader = protectedLoader(({ params }) => {
  const id = params.id as string;

  return {
    queryRef: preloadQuery(TournamentQuery, {
      variables: {
        id,
      },
      fetchPolicy: 'cache-and-network',
      returnPartialData: true,
    }),
  };
});

as soon as I remove returnPartialData the error throws and my error boundary is rendered