apollographql / apollographql/apollo-client-integrations

`useSuspenseQuery` data is nullish despite the docs saying otherwise

Open
#527 9 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
556
Forks
53
PR merge metrics
No merged PRs in 30d

Description

I have a question about this example within the docs under [Fetching with Suspense](https://www.apollographql.com/docs/react/data/suspense#fetching-with-suspense).

There is a note that says plainly that `data` is guaranteed to be defined, however in my case, I'm having some issues. I've modified the snipped below slightly to illustrate the problem.

Image

### Setup

For my particular case, I'm using `PreloadQuery` and colocated fragments in a server component that starts `GET_DOG_QUERY` on the server, meaning that client query should be "simulated", picking up the result from the one started on the server...

```typescript
// on the server

// ... some server stuff

return (

Loading doggo...}>



);
```

### Nuanced example

``` typescript
"use client"

import { Suspense } from "react";
import { gql, TypedDocumentNode } from "@apollo/client";
import { useSuspenseQuery, useSuspenseFragment } from "@apollo/client/react";

interface Data {
dog: {
id: string;
name: string;
};
}

interface Variables {
id: string;
}

interface DogProps {
id: string;
}

// This query needs to be declared elsewhere as this is a client component
// and so can't live here and be imported into server component to be used in PreloadQuery
// I simply abstracted it nearby
const GET_DOG_QUERY: TypedDocumentNode = gql`
query GetDog($id: String) {
dog(id: $id) {
# By default, an object's cache key is a combination of
# its __typename and id fields, so we should always make
# sure the id is in the response so our data can be
# properly cached.
id

...ColocatedFragmentWithNameAndBreed
# name
# breed
}
}
`;

function Dog({ id }: DogProps) {

// This is now a simulated query as it's preloaded on the server
const { data } = useSuspenseQuery(GET_DOG_QUERY, {
variables: { id },
});

// a few observations...
// 1. data.dog.name is masked because this component declares its data requirement with a fragment
// 2. we therefore have to unpack the masked fragment to get the data, which I'm doing as below in my project
// 3. data is not guaranteed as far as the ts compiler is concerned meaning that I have to assert it as non-null or type cast it

// const dog = data.dog as Pick, "dog">; - don't want to do this!

const { data: fragmentData } = useSuspenseFragment({
fragment: GET_DOG_QUERY,
fragmentName: "ColocatedFragmentWithNameAndBreed",
from: data.dog, // this isn't guaranteed - but is happy if I pass dog or assert non-null!
});

return <>Name: {fragmentData.name};
}
```

#### Context
I should mention that I'm working in NextJS using the app router and `@apollo/client-integration-nextjs`. I use TypedDocumentNode and Codegen with masking configured correctly, so far as I can tell.

I'm really wanting to get on board with this new way of working with ApolloClient, but it was quite painful DX to get to even this point. The docs, which extensive feel like they have a lot of indirection. Is it a skill issue?

Are there examples in a repository somewhere? If so, maybe that needs improved discoverability as I've combed the docs many times, watched the talk, read the slides and am yet to see actual app-based patterns.

Anyway, what I have here works, but asserting non-null or casting feels a little unsavoury to me.

It's also one thing for me to find my way through this complexity, but trying to get an engineering team to adopt this will be a new challenge I'm not really looking forward to.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the linked Fetching with Suspense documentation and reproduce the TypeScript behavior using the shown useSuspenseQuery, useSuspenseFragment, PreloadQuery, and Next.js integration setup. Determine whether the nullish type comes from the documented API, fragment masking, or the integration, then update the relevant behavior or documentation so the guarantee and completed result are unambiguous.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, nextjs, react, typescript
Domain
developer-experience, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.