You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: docs/source/data/suspense.mdx
+60-22
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
---
2
2
title: Suspense
3
-
description: Using React 18 Suspense features with Apollo Client
3
+
description: Use React 18 Suspense features with Apollo Client
4
4
minVersion: 3.8.0
5
5
---
6
6
@@ -70,13 +70,21 @@ function Dog({ id }: DogProps) {
70
70
}
71
71
```
72
72
73
-
> **Note:** This example manually defines TypeScript interfaces for `Data` and `Variables` as well as the type for `GET_DOG_QUERY` using `TypedDocumentNode`. [GraphQL Code Generator](https://www.the-guild.dev/graphql/codegen) is a popular tool that creates these type definitions automatically for you. See the reference on [Using TypeScript](../development-testing/static-typing) for more information on integrating GraphQL Code Generator with Apollo Client.
73
+
<Note>
74
+
75
+
This example manually defines TypeScript interfaces for `Data` and `Variables` as well as the type for `GET_DOG_QUERY` using `TypedDocumentNode`. [GraphQL Code Generator](https://www.the-guild.dev/graphql/codegen) is a popular tool that creates these type definitions automatically for you. See the reference on [Using TypeScript](../development-testing/static-typing) for more information on integrating GraphQL Code Generator with Apollo Client.
76
+
77
+
</Note>
74
78
75
79
In this example, our `App` component renders a `Dog` component which fetches the record for a single dog via `useSuspenseQuery`. When React attempts to render `Dog` for the first time, the cache is unable to fulfill the request for the `GetDog` query, so `useSuspenseQuery` initiates a network request. `Dog` suspends while the network request is pending, triggering the nearest `Suspense` boundary _above_ the suspended component in `App` which renders our "Loading..." fallback. Once the network request is complete, `Dog` renders with the newly cached `name` for Mozzarella the Corgi.
76
80
77
81
You may have noticed that `useSuspenseQuery` does not return a `loading` boolean. That's because the component calling `useSuspenseQuery` always suspends when fetching data. A corollary is that when it _does_ render, `data` is always defined! In the Suspense paradigm, fallbacks that exist **outside of suspended components** replace the loading states components were previously responsible for rendering themselves.
78
82
79
-
> **Note for TypeScript users**: Since `GET_DOG_QUERY` is a `TypedDocumentNode` in which we have specified the result type via `Data` generic type argument, the TypeScript type for `data` returned by `useSuspenseQuery` reflects that! This means that `data` is guaranteed to be defined when `Dog` renders, and that `data.dog` has the shape `{ id: string; name: string; breed: string; }`.
83
+
<Note>
84
+
85
+
**For TypeScript users**: Since `GET_DOG_QUERY` is a `TypedDocumentNode` in which we have specified the result type via `Data` generic type argument, the TypeScript type for `data` returned by `useSuspenseQuery` reflects that! This means that `data` is guaranteed to be defined when `Dog` renders, and that `data.dog` has the shape `{ id: string; name: string; breed: string; }`.
86
+
87
+
</Note>
80
88
81
89
### Changing variables
82
90
@@ -230,7 +238,11 @@ function App() {
230
238
231
239
When the cache contains partial data, you may prefer to render that data immediately without suspending. To do this, use the `returnPartialData` option.
232
240
233
-
> **Note:** This option only works when combined with either the `cache-first` (default) or `cache-and-network` fetch policy. `cache-only` is not currently supported by `useSuspenseQuery`. For details on these fetch policies, see [Setting a fetch policy](/react/data/queries/#setting-a-fetch-policy).
241
+
<Note>
242
+
243
+
This option only works when combined with either the `cache-first` (default) or `cache-and-network` fetch policy. `cache-only` isn't currently supported by `useSuspenseQuery`. For details on these fetch policies, see [Setting a fetch policy](/react/data/queries/#setting-a-fetch-policy).
244
+
245
+
</Note>
234
246
235
247
Let's update our example to use the partial cache data and render immediately:
236
248
@@ -291,13 +303,21 @@ In this example, we write partial data to the cache for Buck in order to show th
291
303
292
304
On first render, Buck's name is displayed after the `Name` label, followed by the `Breed` label with no value. Once the missing fields have loaded, `useSuspenseQuery` triggers a re-render and Buck's breed is displayed.
293
305
294
-
> **Note for TypeScript users**: With `returnPartialData` set to `true`, the returned type for the `data` property marks all fields in the query type as [optional](https://www.typescriptlang.org/docs/handbook/2/objects.html#optional-properties). Apollo Client cannot accurately determine which fields are present in the cache at any given time when returning partial data.
306
+
<Note>
307
+
308
+
**For TypeScript users**: With `returnPartialData` set to `true`, the returned type for the `data` property marks all fields in the query type as [optional](https://www.typescriptlang.org/docs/handbook/2/objects.html#optional-properties). Apollo Client cannot accurately determine which fields are present in the cache at any given time when returning partial data.
309
+
310
+
</Note>
295
311
296
312
### Error handling
297
313
298
314
By default, both network errors and GraphQL errors are thrown by `useSuspenseQuery`. These errors are caught and displayed by the closest [error boundary](https://react.dev/reference/react/Component#static-getderivedstatefromerror).
299
315
300
-
> **Note:** An error boundary is a **class component** that implements `static getDerivedStateFromError`. For more information, see the React docs for [catching rendering errors with an error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary).
316
+
<Note>
317
+
318
+
An error boundary is a **class component** that implements `static getDerivedStateFromError`. For more information, see the React docs for [catching rendering errors with an error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary).
319
+
320
+
</Note>
301
321
302
322
Let's create a basic error boundary that renders an error UI when errors are thrown by our query:
303
323
@@ -322,7 +342,11 @@ class ErrorBoundary extends React.Component {
322
342
}
323
343
```
324
344
325
-
> **Note:** In a real application, your error boundary might need a more robust implementation. Consider using a library like [`react-error-boundary`](https://github.com/bvaughn/react-error-boundary) when you need a high degree of flexibility and reusability.
345
+
<Note>
346
+
347
+
In a real application, your error boundary might need a more robust implementation. Consider using a library like [`react-error-boundary`](https://github.com/bvaughn/react-error-boundary) when you need a high degree of flexibility and reusability.
348
+
349
+
</Note>
326
350
327
351
When the `GET_DOG_QUERY` inside of the `Dog` component returns a GraphQL error or a network error, `useSuspenseQuery` throws the error and the nearest error boundary renders its fallback component.
328
352
@@ -360,7 +384,11 @@ function App() {
360
384
361
385
Here, we're using our `ErrorBoundary` component and placing it **outside** of our `Dog` component. Now, when the `useSuspenseQuery` hook inside the `Dog` component throws an error, the `ErrorBoundary` catches it and displays the `fallback` element we've provided.
362
386
363
-
> **Note:** When working with many React frameworks, you may see an error dialog overlay in development mode when errors are thrown, even _with_ an error boundary. This is done to avoid the error being missed by developers.
387
+
<Note>
388
+
389
+
When working with many React frameworks, you may see an error dialog overlay in development mode when errors are thrown, even _with_ an error boundary. This is done to avoid the error being missed by developers.
390
+
391
+
</Note>
364
392
365
393
#### Rendering partial data alongside errors
366
394
@@ -427,7 +455,11 @@ We begin fetching our `GET_BREEDS_QUERY` when the `App` component renders. The n
427
455
428
456
When the network request for `GET_DOG_QUERY` completes, the `Dog` component unsuspends and continues rendering, reaching the `Breeds` component. Since our `GET_BREEDS_QUERY` request was initiated higher up in our component tree using `useBackgroundQuery`, the network request for `GET_BREEDS_QUERY`**has already completed**! When the `Breeds` component reads the data from the `queryRef` provided by `useBackgroundQuery`, it avoids suspending and renders immediately with the fetched data.
429
457
430
-
> **Note:** When the `GET_BREEDS_QUERY` takes _longer_ to fetch than our `GET_DOG_QUERY`, `useReadQuery` suspends and the Suspense fallback inside of the `Dog` component is rendered instead.
458
+
<Note>
459
+
460
+
When the `GET_BREEDS_QUERY` takes _longer_ to fetch than our `GET_DOG_QUERY`, `useReadQuery` suspends and the Suspense fallback inside of the `Dog` component is rendered instead.
461
+
462
+
</Note>
431
463
432
464
#### A note about performance
433
465
@@ -439,7 +471,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick
439
471
440
472
</MinVersion>
441
473
442
-
`useSuspenseQuery` and `useBackgroundQuery`are useful for loading data as soon as the component calling the hook mounts. But what about loading a query in response to user interaction? For example, we may want to start loading some data when a user hovers on a link.
474
+
The `useSuspenseQuery` and `useBackgroundQuery`hooks let us load data as soon as the component calling the hook mounts. But what about loading a query in response to user interaction? For example, we may want to start loading some data when a user hovers on a link.
443
475
444
476
Available as of Apollo Client `3.9.0`, the `useLoadableQuery` hook initiates a network request in response to user interaction.
445
477
@@ -493,7 +525,9 @@ function Dog({ queryRef }: DogProps) {
493
525
}
494
526
```
495
527
496
-
We begin fetching our `GET_DOG_QUERY` by calling the `loadDog` function inside of the `onChange` handler function when a dog is selected. Once the network request is initiated, the `queryRef` is no longer `null` which renders the `Dog` component. In the `Dog` component, `useReadQuery` suspends the component while the network request finishes, then returns `data` to the component. As a result of this change, we've also eliminated the need to track the selected dog `id` in component state!
528
+
We begin fetching our `GET_DOG_QUERY` by calling the `loadDog` function inside of the `onChange` handler function when a dog is selected. Once the network request is initiated, the `queryRef` is no longer `null`, rendering the `Dog` component.
529
+
530
+
`useReadQuery` suspends the `Dog` component while the network request finishes, then returns `data` to the component. As a result of this change, we've also eliminated the need to track the selected dog `id` in component state.
497
531
498
532
<MinVersionversion="3.9.0">
499
533
@@ -503,11 +537,11 @@ We begin fetching our `GET_DOG_QUERY` by calling the `loadDog` function inside o
503
537
504
538
<ExperimentalFeature>
505
539
506
-
This feature is in [alpha stage](https://www.apollographql.com/docs/resources/product-launch-stages/#alpha--beta)for version `3.9.0` and may be subject to change before `3.10.0`. We consider this feature production-ready, but may be subject to change depending on feedback. If you'd like to provide feedback for this feature before it is stabilized in `3.10.0`, please visit [#11519](https://github.com/apollographql/apollo-client/issues/11519) and add a comment.
540
+
This feature is in [alpha](https://www.apollographql.com/docs/resources/product-launch-stages/#alpha--beta)in version `3.9.0` and is subject to change before `3.10.0`. We consider this feature production-ready, but it may change depending on feedback. If you'd like to provide feedback before it is stabilized in `3.10.0`, please comment on [#11519](https://github.com/apollographql/apollo-client/issues/11519).
507
541
508
542
</ExperimentalFeature>
509
543
510
-
Starting with Apollo Client `3.9.0`, queries can be initiated outside of React. This allows your app to begin fetching data _before_ React renders your components, and can provide performance benefits.
544
+
Starting with Apollo Client `3.9.0`, queries can be initiated outside of React. This allows your app to begin fetching data before React renders your components, and can provide performance benefits.
511
545
512
546
To preload queries, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` takes an `ApolloClient` instance as an argument and returns a function that, when called, initiates a network request.
513
547
@@ -517,7 +551,7 @@ Consider exporting your preload function along with your `ApolloClient` instance
517
551
518
552
</Tip>
519
553
520
-
The preload function returns a `queryRef` that is passed to `useReadQuery` to read the query data and suspend the component while loading. `useReadQuery`will ensure that your component is kept up-to-date with cache updates for the preloaded query.
554
+
The preload function returns a `queryRef` that is passed to `useReadQuery` to read the query data and suspend the component while loading. `useReadQuery`ensures that your component is kept up-to-date with cache updates for the preloaded query.
521
555
522
556
523
557
Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered.
@@ -565,7 +599,7 @@ root.render(
565
599
);
566
600
```
567
601
568
-
We begin loading data as soon as our `preloadQuery` function is called rather than waiting for React to render our `<App />` component. Because the `preloadedQueryRef` is passed to `useReadQuery` in our `App` component, we still get the benefit of suspense and cache updates!
602
+
We begin loading data as soon as our `preloadQuery` function is called rather than waiting for React to render our `<App />` component. Because the `preloadedQueryRef` is passed to `useReadQuery` in our `App` component, we still get the benefit of suspense and cache updates.
569
603
570
604
<Note>
571
605
@@ -575,9 +609,11 @@ Unmounting components that contain preloaded queries is safe and disposes of the
575
609
576
610
#### Usage with data loading routers
577
611
578
-
Popular routers such as [React Router](https://reactrouter.com/en/main) and [TanStack Router](https://tanstack.com/router) provide APIs to load data before route components are rendered (e.g. such as the [`loader` function](https://reactrouter.com/en/main/route/route#loader) from React Router). This is especially useful for nested routes where data loading is parallelized and prevents situtations where parent route components might otherwise suspend and create request waterfalls for child route components.
612
+
Popular routers such as [React Router](https://reactrouter.com/en/main) and [TanStack Router](https://tanstack.com/router) provide APIs to load data before route components are rendered. One example is the [`loader` function](https://reactrouter.com/en/main/route/route#loader) from React Router.
579
613
580
-
`preloadQuery` pairs nicely with these router APIs as it lets you take advantage of those optimizations without sacrificing the ability to rerender with cache updates in your route components.
614
+
Loading data before rendering route components is especially useful for nested routes where data loading is parallelized. It prevents situations where parent route components might otherwise suspend and create request waterfalls for child route components.
615
+
616
+
`preloadQuery` pairs nicely with these router APIs as it lets you take advantage of those optimizations without sacrificing the ability to rerender cache updates in your route components.
581
617
582
618
Let's update our example using React Router's `loader` function to begin loading data when we transition to our route.
583
619
@@ -600,19 +636,21 @@ export function RouteComponent() {
600
636
601
637
> The `loader` function is available in React Router versions 6.4 and above.
602
638
603
-
React Router calls the `loader` function which we use to begin loading the `GET_DOG_QUERY` query by calling the `preloadQuery` function. The `queryRef` created by `preloadQuery` is returned from the `loader` function making it accessible in the route component. When the route component renders, we access the `queryRef` from the `useLoaderData` hook, which is then passed to `useReadQuery`. We get the benefit of loading our data early in the routing lifecycle, while our route component maintains the ability to rerender with cache updates!
639
+
React Router calls the `loader` function which we use to begin loading the `GET_DOG_QUERY` query by calling the `preloadQuery` function. The `queryRef` created by `preloadQuery` is returned from the `loader` function making it accessible in the route component.
640
+
641
+
When the route component renders, we access the `queryRef` from the `useLoaderData` hook, which is then passed to `useReadQuery`. We get the benefit of loading our data early in the routing lifecycle, and the route component maintains the ability to rerender with cache updates.
604
642
605
643
<Note>
606
644
607
-
The `preloadQuery` function only works with client-side routing. The `queryRef` returned from `preloadQuery`is not serializable across the wire and as such, will not work with routers that fetch on the server such as [Remix](https://remix.run/).
645
+
The `preloadQuery` function only works with client-side routing. The `queryRef` returned from `preloadQuery`isn't serializable across the wire and as such, won't work with routers that fetch on the server such as [Remix](https://remix.run/).
608
646
609
647
</Note>
610
648
611
649
#### Preventing route transitions until the query is loaded
612
650
613
-
By default, `preloadQuery` works similar to a [deferred loader](https://reactrouter.com/en/main/guides/deferred): the route will transition immediately and the incoming page that's attempting to read the data via `useReadQuery`will suspend until the network request finishes.
651
+
By default, `preloadQuery` works similarly to a [deferred loader](https://reactrouter.com/en/main/guides/deferred): the route transitions immediately and the incoming page that's attempting to read the data via `useReadQuery`suspends until the network request finishes.
614
652
615
-
But what if we want to prevent the route from transitioning until the data is fully loaded? The`toPromise` method on a `queryRef` provides access to a promise that resolves when the network request has completed. This promise resolves with the `queryRef` itself, making it easy to use with hooks such as `useLoaderData`.
653
+
But what if we want to prevent the route from transitioning until the data is fully loaded? `queryRef`'s`toPromise` method provides access to a promise that resolves when the network request has completed. This promise resolves with the `queryRef` itself, making it easy to use with hooks such as `useLoaderData`.
616
654
617
655
Here's an example:
618
656
@@ -641,7 +679,7 @@ This instructs React Router to wait for the query to finish loading before the r
641
679
642
680
<ExperimentalFeature>
643
681
644
-
`queryRef.toPromise` is [experimental](https://www.apollographql.com/docs/resources/product-launch-stages/#experimental-features)for version `3.9.0` and may be subject to breaking changes before `3.10.0`. If you'd like to provide feedback for this feature before it is stabilized in `3.10.0`, please visit [#11519](https://github.com/apollographql/apollo-client/issues/11519) and add a comment.
682
+
`queryRef.toPromise` is [experimental](https://www.apollographql.com/docs/resources/product-launch-stages/#experimental-features)in version `3.9.0` and is subject to breaking changes before `3.10.0`. If you'd like to provide feedback for this feature before it is stabilized in `3.10.0`, please comment on [#11519](https://github.com/apollographql/apollo-client/issues/11519).
0 commit comments