From c4f727cb4664de764e1517d1bd994af4f61ba3c2 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 15:43:58 -0700 Subject: [PATCH 01/65] Add section in Suspense docs for `useLoadableQuery` --- docs/source/data/suspense.mdx | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 7db3ceeb09e..636d7522930 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -433,6 +433,59 @@ When the network request for `GET_DOG_QUERY` completes, the `Dog` component unsu The `useBackgroundQuery` hook used in a parent component is responsible for kicking off fetches, but doesn't deal with reading or rendering data. This is delegated to the `useReadQuery` hook used in a child component. This separation of concerns provides a nice performance benefit because cache updates are observed by `useReadQuery` and re-render only the child component. You may find this as a useful tool to optimize your component structure to avoid unnecessarily re-rendering parent components when cache data changes. + + +### Querying in response to user interaction + + + +`useSuspenseQuery` and `useBackgroundQuery` are useful hooks that will begin loading data as soon as the hook is mounted. But what happens when you'd like to start loading your query in response to a user interaction? With `useSuspenseQuery` and `useBackgroundQuery`, you'd need to update React state in response to the user interaction in order to re-render your component. + +Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This is not only more ergonomic, but starts loading the query immediately, providing a nice performance benefit. + +`useLoadableQuery` returns a function that when called will begin fetching the query with the provided variables. Like `useBackgroundQuery`, you get access to a `queryRef` that is passed to `useReadQuery` to read the data in a child component. When the child component renders before the query has finished loading, the child component suspends. + +Let's update our example to start loading the dog's details as a result of selecting from a dropdown. + +```tsx +function App() { + const { data } = useSuspenseQuery(GET_DOGS_QUERY); + const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY) + + return ( + <> + + Loading...}> + {queryRef && } + + + ); +} + +function Dog({ queryRef }) { + const { data } = useReadQuery(queryRef) + + return ( + <> +
Name: {data.dog.name}
+
Breed: {data.dog.breed}
+ + ); +} +``` + +> It's important to note that the `queryRef` is `null` until the query loading function is called for the first time. You should conditionally render the child component when the query has not yet been loaded. + +We begin fetching our `GET_DOG_QUERY` as soon as a new dog is selected rather than waiting for our `Dog` component to re-render. When the `Dog` component renders, it reads data from the `GET_DOG_QUERY`, and if not ready, will suspend. As a result of this change, we've also removed the need to track the selected dog ID as part of React state! + ### Refetching and pagination Apollo's Suspense data fetching hooks return functions for refetching query data via the `refetch` function, and fetching additional pages of data via the `fetchMore` function. From 08eb80e6ffa12f34c0759000a82c143c8812fe8a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 15:52:38 -0700 Subject: [PATCH 02/65] Move dogs to props in example to avoid call to `useSuspenseQuery` --- docs/source/data/suspense.mdx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 636d7522930..e8ff99b45f4 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -448,8 +448,7 @@ Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loa Let's update our example to start loading the dog's details as a result of selecting from a dropdown. ```tsx -function App() { - const { data } = useSuspenseQuery(GET_DOGS_QUERY); +function App({ dogs }) { const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY) return ( @@ -457,7 +456,7 @@ function App() { loadDog({ id: e.target.value })} > - {dogs.map(({ id, name }) => ( + {data.dogs.map(({ id, name }) => ( @@ -485,6 +486,129 @@ function Dog({ queryRef }) { We begin fetching our `GET_DOG_QUERY` as soon as a new dog is selected rather than waiting for our `Dog` component to re-render. When the `Dog` component renders, it reads data from the `GET_DOG_QUERY`, and if not ready, will suspend. As a result of this change, we've also removed the need to track the selected dog ID as part of React state! + + +### Initiating queries outside React + + + +Starting with Apollo Client `3.9.0`, it is possible to start loading queries outside React. This avoids the need to wait for React to render your components before the query begins loading, providing a nice performance benefit. + + + +This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifically looking for user feedback on the API design choices. The underlying behavior is otherwise fully implemented. If you'd like to provide feedback for this feature before it is stabilized in `3.10.0`, please [open an issue](https://github.com/apollographql/apollo-client/issues/new). + + + +To begin loading data immediately, you first need to create a preloading function with `createQueryPreloader`. `createQueryPreloader` is given the `client` as an argument and returns a function that when called, will begin fetching the query. The preload function returns a `queryRef` that can then be passed to `useReadQuery` to read the query data, and if still loading, suspend that component. + +Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered. + +```tsx {1-2,5,28,30} +const preloadQuery = createQueryPreloader(client); +const dogsQueryRef = preloadQuery(GET_DOGS_QUERY); + +function App() { + const { data } = useReadQuery(dogsQueryRef); + const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY) + + return ( + <> + + Loading...}> + + + + ); +} + +const root = createRoot(document.getElementById('app')); + +root.render( + + Loading...}> + + + +); +``` + +We begin loading data as soon as our `preloadQuery` function is called. We no longer need to wait for React to render our `` component before our `GET_DOGS_QUERY` begins loading, but still get the benefit of suspense! + +#### Usage with routers + +Popular routers such as [React Router](https://reactrouter.com/en/main) and [TanStack Router](https://tanstack.com/router) include APIs to start loading data before the route component renders (e.g. such as the [`loader` function](https://reactrouter.com/en/main/route/route#loader) from React Router). These APIs have the benefit that they can begin loading data in parallel without the need to wait for the route component to render. This is especially useful for nested routes where a parent route would otherwise suspend and create request waterfalls for child routes. + +The `preloadQuery` API pairs nicely with these router APIs as it lets you take advantage of the optimizations these routers provide without sacrificing the ability to respond to cache updates in your route components. + +Let's update our example using React Router's `loader` function to begin loading data when we transition to our route. + +```ts +import { useLoaderData } from 'react-router-dom'; + +export function loader() { + return preloadQuery(GET_DOGS_QUERY); +} + +export function RouteComponent() { + const queryRef = useLoaderData(); + const { data } = useReadQuery(queryRef); + + return ( + // ... + ); +} +``` + +> Note: The `loader` function is only available in React Router versions 6.4 and above. + +We load our query as soon as React Router calls our `loader` function. This starts fetching before our route component is rendered. When our route component renders, we can get access to the `queryRef`, which is passed to `useReadQuery` to read the data. This means our route component has the ability to update itself when our cache is updated! + + + +The `preloadQuery` API 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 render on the server, such as [Remix](https://remix.run/). + + + +#### Preventing route transitions until the query is loaded + +By default, `preloadQuery` works similar to a [deferred loader](https://reactrouter.com/en/main/guides/deferred) in that routes will transition immediately and suspend with `useReadQuery` until the query is loaded. You may instead want to prevent the route from transitioning until the data is fully loaded. Use the `toPromise` method on the `queryRef` to get a promise that resolves when the query is loaded. This promise resolves with the `queryRef` itself, making it easy to use with hooks such as `useLoaderData`. + +```ts +export async function loader() { + const queryRef = await preloadQuery(GET_DOGS_QUERY).toPromise(); + + return queryRef; +} + +// You may also return the promise directly from loader. +// This is equivalent to the above. +export async function loader() { + return preloadQuery(GET_DOGS_QUERY).toPromise(); +} + +export function RouteComponent() { + const queryRef = useLoaderData(); + const { data } = useReadQuery(queryRef); + + // ... +} +``` + +This instructs React Router to wait for the query to finish loading before the route transitions. When the route does transition, the data will be rendered immediately without the need to show a loading fallback in the route component. + +#### Why prevent access to `data` in `toPromise`? + +You may be wondering why we resolve `toPromise` with the `queryRef` itself, rather than the data loaded from the query. This is because we want to encourage you to leverage `useReadQuery` to avoid missing out on cache updates for your query. If `data` were available, it would be tempting to consume it in your `loader` functions and expose it to your route components. Doing so means missing out on cache updates. + +If you need access to raw query data in your `loader` functions, use [`client.query()`](../api/core/ApolloClient#query) directly. + ### Refetching and pagination Apollo's Suspense data fetching hooks return functions for refetching query data via the `refetch` function, and fetching additional pages of data via the `fetchMore` function. From fefd6a4a23923097a4710962476138adb96a06ff Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 18:20:20 -0700 Subject: [PATCH 05/65] Add section on `useQueryRefHandlers` --- docs/source/data/suspense.mdx | 121 ++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index a3771055892..927f6bc04b3 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -689,6 +689,127 @@ function Breeds({ queryRef, isPending }: BreedsProps) { In this example, our `App` component renders a `Dog` component that fetches a single dog's record via `useSuspenseQuery`. When React attempts to render `Dog` for the first time, the cache can't 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 the dog whose `id="3"`: Mozzarella the Corgi. +#### Usage with query preloading + +When loading queries [outside React](#initiating-queries-outside-react), the `preloadQuery` function returns a `queryRef` with no access to `refetch` or `fetchMore` functions. This presents a challenge if you need to refresh or paginate on the data returned by the query ref. + +You can gain access to `refetch` and `fetchMore` functions by using the `useQueryRefHandlers` hook. This hook integrates with React transitions, giving you the ability to update without suspending. + +Let's update our example to preload our `GET_BREEDS_QUERY` outside React and utilize `useQueryRefHandlers` to refetch our query. + +```tsx {4,7-8,12} +// ... +import { + // ... + useQueryRefHandlers, +} from "@apollo/client"; + +const preloadQuery = createQueryPreloader(client); +const queryRef = preloadQuery(GET_BREEDS_QUERY); + +function App() { + const [isPending, startTransition] = useTransition(); + const { refetch } = useQueryRefHandlers(queryRef); + + function handleRefetch() { + startTransition(() => { + refetch(); + }); + }; + + return ( + Loading...}> + + + ); +} + +function Dog({ + id, + isPending, + onRefetch, +}: DogProps) { + const { data } = useSuspenseQuery(GET_DOG_QUERY, { + variables: { id }, + }); + + return ( + <> + Name: {data.dog.name} + Loading breeds...}> + + + + + ); +} + +function Breeds({ isPending }: BreedsProps) { + const { data } = useReadQuery(queryRef); + + return data.breeds.map(({ characteristics }) => + characteristics.map((characteristic) => ( +
+ {characteristic} +
+ )) + ); +} +``` + +We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We use the `useQueryRefHandlers` hook to get access to the `refetch` function which lets us reload the query when the button is clicked. + +#### Accessing query ref handlers produced from other hooks + +`useQueryRefHandlers` is not limited to the `preloadQuery` API and can be used with any hook that produces a `queryRef` such as `useBackgroundQuery` or `useLoadableQuery`. This can be useful in situations where you may need access to the `refetch` and `fetchMore` functions in components where the `queryRef` was passed through deeply. + +Let's update our last example back to `useBackgroundQuery` and get access to `refetch` in our `Dog` component instead without needing to pass it from the parent. + +```tsx {12,16,18-22,30} +function App() { + const [queryRef] = useBackgroundQuery(GET_BREEDS_QUERY); + + return ( + Loading...}> + + + ); +} + +function Dog({ id, queryRef }: DogProps) { + const [isPending, startTransition] = useTransition(); + const { data } = useSuspenseQuery(GET_DOG_QUERY, { + variables: { id }, + }); + const { refetch } = useQueryRefHandlers(queryRef); + + function handleRefetch() { + startTransition(() => { + refetch(); + }); + }; + + return ( + <> + Name: {data.dog.name} + Loading breeds...}> + + + + + ); +} + +// ... +``` + ## Distinguishing between queries with `queryKey` Apollo Client uses the combination of `query` and `variables` to uniquely identify each query when using Apollo's Suspense data fetching hooks. From ebe870012fb8cfb6708f0b6231078a865dfc0182 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 20:08:54 -0700 Subject: [PATCH 06/65] Add note about API for useQueryRefHandlers --- docs/source/data/suspense.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 927f6bc04b3..a6776bb806f 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -877,6 +877,10 @@ More details on `useBackgroundQuery`'s API can be found in [its API docs](../api More details on `useLoadableQuery`'s API can be found in [its API docs](../api/react/hooks/#useloadablequery). +## useQueryRefHandlers API + +More details on `useQueryRefHandlers`'s API can be found in [its API docs](../api/react/hooks/#usequeryrefhandlers). + ## useReadQuery API More details on `useReadQuery`'s API can be found in [its API docs](../api/react/hooks/#usereadquery). From 908a1e75032b148782b9adb1d56b797f9367bc88 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 20:34:50 -0700 Subject: [PATCH 07/65] Provide imports in code samples --- docs/source/data/suspense.mdx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index a6776bb806f..37639a8ad9f 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -447,7 +447,12 @@ Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loa Let's update our example to start loading the dog's details as a result of selecting from a dropdown. -```tsx {3,8,17,24} +```tsx {3,8,13,22,29} +import { + // ... + useLoadableQuery +} from '@apollo/client'; + function App() { const { data } = useSuspenseQuery(GET_DOGS_QUERY); const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY) @@ -504,7 +509,12 @@ To begin loading data immediately, you first need to create a preloading functio Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered. -```tsx {1-2,5,28,30} +```tsx {3,6-7,10,33,35} +import { + // ... + createQueryPreloader +} from '@apollo/client'; + const preloadQuery = createQueryPreloader(client); const dogsQueryRef = preloadQuery(GET_DOGS_QUERY); From 28ab24d9ab4ceea339cb7a4128e68eee223f010c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 20:54:32 -0700 Subject: [PATCH 08/65] Add more context about design of `createQueryPreloader` --- docs/source/data/suspense.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 37639a8ad9f..48faee1f643 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -505,7 +505,9 @@ This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifica -To begin loading data immediately, you first need to create a preloading function with `createQueryPreloader`. `createQueryPreloader` is given the `client` as an argument and returns a function that when called, will begin fetching the query. The preload function returns a `queryRef` that can then be passed to `useReadQuery` to read the query data, and if still loading, suspend that component. +To begin loading data immediately, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` is given an `ApolloClient` instance as an argument and returns a function that when called, will begin fetching the query. By making `createQueryPreloader` a [curried](https://en.wikipedia.org/wiki/Currying) function, this makes it easy to export your preload function alongside any `ApolloClient` instance you create. + +The preload function returns a `queryRef` that can then be passed to `useReadQuery` to read the query data and suspend the component while loading. `useReadQuery` will also ensure that your component containing the preloaded query will be kept up-to-date with any cache updates for that query. Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered. From 431e55cefac460871864d88967297838cd63b0e6 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 20:54:44 -0700 Subject: [PATCH 09/65] Rename variable used in preload query example --- docs/source/data/suspense.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 48faee1f643..88cb62bfe7b 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -518,10 +518,10 @@ import { } from '@apollo/client'; const preloadQuery = createQueryPreloader(client); -const dogsQueryRef = preloadQuery(GET_DOGS_QUERY); +const preloadedQueryRef = preloadQuery(GET_DOGS_QUERY); function App() { - const { data } = useReadQuery(dogsQueryRef); + const { data } = useReadQuery(preloadedQueryRef); const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY) return ( From 4434d90b34a154f18a311e11f45e6b37f6160fa1 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 20:58:19 -0700 Subject: [PATCH 10/65] Update headline for routers --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 88cb62bfe7b..dee6b27cb7a 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -553,7 +553,7 @@ root.render( We begin loading data as soon as our `preloadQuery` function is called. We no longer need to wait for React to render our `` component before our `GET_DOGS_QUERY` begins loading, but still get the benefit of suspense! -#### Usage with routers +#### Usage with data loading routers Popular routers such as [React Router](https://reactrouter.com/en/main) and [TanStack Router](https://tanstack.com/router) include APIs to start loading data before the route component renders (e.g. such as the [`loader` function](https://reactrouter.com/en/main/route/route#loader) from React Router). These APIs have the benefit that they can begin loading data in parallel without the need to wait for the route component to render. This is especially useful for nested routes where a parent route would otherwise suspend and create request waterfalls for child routes. From 249978903cce87c2511ed306c174e32e26f0b9de Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:00:02 -0700 Subject: [PATCH 11/65] Minor tweak to routing section --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index dee6b27cb7a..10dc1dca7e0 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -555,7 +555,7 @@ We begin loading data as soon as our `preloadQuery` function is called. We no lo #### Usage with data loading routers -Popular routers such as [React Router](https://reactrouter.com/en/main) and [TanStack Router](https://tanstack.com/router) include APIs to start loading data before the route component renders (e.g. such as the [`loader` function](https://reactrouter.com/en/main/route/route#loader) from React Router). These APIs have the benefit that they can begin loading data in parallel without the need to wait for the route component to render. This is especially useful for nested routes where a parent route would otherwise suspend and create request waterfalls for child routes. +Popular routers such as [React Router](https://reactrouter.com/en/main) and [TanStack Router](https://tanstack.com/router) include APIs to start loading data before the route component renders (e.g. such as the [`loader` function](https://reactrouter.com/en/main/route/route#loader) from React Router). These APIs have the benefit that they can begin loading data in parallel without the need to wait for the route components to render. This is especially useful for nested routes where a parent route might otherwise suspend and create request waterfalls for child routes. The `preloadQuery` API pairs nicely with these router APIs as it lets you take advantage of the optimizations these routers provide without sacrificing the ability to respond to cache updates in your route components. From bb96e55810105045c2ec8c7bccde44b17e158f6a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:01:27 -0700 Subject: [PATCH 12/65] Highlight code in router example --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 10dc1dca7e0..4964845e97e 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -561,7 +561,7 @@ The `preloadQuery` API pairs nicely with these router APIs as it lets you take a Let's update our example using React Router's `loader` function to begin loading data when we transition to our route. -```ts +```ts {4,8-9} import { useLoaderData } from 'react-router-dom'; export function loader() { From e5d6c6fbb7bfea5ee6e63925fff475c0d60917c3 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:01:48 -0700 Subject: [PATCH 13/65] Minor tweak to note about react router --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 4964845e97e..87b2addb390 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -578,7 +578,7 @@ export function RouteComponent() { } ``` -> Note: The `loader` function is only available in React Router versions 6.4 and above. +> Note: The `loader` function is available in React Router versions 6.4 and above. We load our query as soon as React Router calls our `loader` function. This starts fetching before our route component is rendered. When our route component renders, we can get access to the `queryRef`, which is passed to `useReadQuery` to read the data. This means our route component has the ability to update itself when our cache is updated! From a7cf9337a21754a76b8fb61d9539fa4c57a36349 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:03:30 -0700 Subject: [PATCH 14/65] Tweak to section about router and preloadQuery --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 87b2addb390..21d06eb55de 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -580,7 +580,7 @@ export function RouteComponent() { > Note: The `loader` function is available in React Router versions 6.4 and above. -We load our query as soon as React Router calls our `loader` function. This starts fetching before our route component is rendered. When our route component renders, we can get access to the `queryRef`, which is passed to `useReadQuery` to read the data. This means our route component has the ability to update itself when our cache is updated! +We load our query as soon as React Router calls our `loader` function. This starts fetching before our route component is rendered. When our route component renders, we can get access to the `queryRef` created by our `preloadQuery` function via the `useLoaderData` hook, which is then passed to `useReadQuery` to read the data. We get the benefit of loading our data early in the routing lifecycle, while our route component has the ability to update itself when the cache is updated! From 23c54cc4836d047cff19c04874f0ca124efd9c4e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:05:17 -0700 Subject: [PATCH 15/65] Remove Note: prefix in explainer --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 21d06eb55de..c85a693986a 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -578,7 +578,7 @@ export function RouteComponent() { } ``` -> Note: The `loader` function is available in React Router versions 6.4 and above. +> The `loader` function is available in React Router versions 6.4 and above. We load our query as soon as React Router calls our `loader` function. This starts fetching before our route component is rendered. When our route component renders, we can get access to the `queryRef` created by our `preloadQuery` function via the `useLoaderData` hook, which is then passed to `useReadQuery` to read the data. We get the benefit of loading our data early in the routing lifecycle, while our route component has the ability to update itself when the cache is updated! From 3ab6262f575460a1d11118f2ff775ab9d5bda4b0 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:06:19 -0700 Subject: [PATCH 16/65] Minor tweak to note about SSR --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index c85a693986a..f95c292acc5 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -584,7 +584,7 @@ We load our query as soon as React Router calls our `loader` function. This star -The `preloadQuery` API 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 render on the server, such as [Remix](https://remix.run/). +The `preloadQuery` API 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/). From e2e51e1b18ff3de4e5a3be40f1d9785f28525713 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:07:47 -0700 Subject: [PATCH 17/65] Minor tweak to explainer on loader --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index f95c292acc5..edbd7dd2422 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -613,7 +613,7 @@ export function RouteComponent() { } ``` -This instructs React Router to wait for the query to finish loading before the route transitions. When the route does transition, the data will be rendered immediately without the need to show a loading fallback in the route component. +This instructs React Router to wait for the query to finish loading before the route transitions. When the route transitions after the promise resolves, the data will be rendered immediately without the need to show a loading fallback in the route component. #### Why prevent access to `data` in `toPromise`? From 173c1a4e2b04f8714ea15f7d8f91fd6aa2c52b20 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:12:16 -0700 Subject: [PATCH 18/65] Add more context on explanation of useQueryRefHandlers --- docs/source/data/suspense.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index edbd7dd2422..8df614cc187 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -705,7 +705,7 @@ In this example, our `App` component renders a `Dog` component that fetches a si When loading queries [outside React](#initiating-queries-outside-react), the `preloadQuery` function returns a `queryRef` with no access to `refetch` or `fetchMore` functions. This presents a challenge if you need to refresh or paginate on the data returned by the query ref. -You can gain access to `refetch` and `fetchMore` functions by using the `useQueryRefHandlers` hook. This hook integrates with React transitions, giving you the ability to update without suspending. +You can gain access to `refetch` and `fetchMore` functions by using the `useQueryRefHandlers` hook. This hook integrates with React transitions, giving you the ability to refetch or paginate without showing the loading fallback. Let's update our example to preload our `GET_BREEDS_QUERY` outside React and utilize `useQueryRefHandlers` to refetch our query. @@ -776,13 +776,13 @@ function Breeds({ isPending }: BreedsProps) { } ``` -We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We use the `useQueryRefHandlers` hook to get access to the `refetch` function which lets us reload the query when the button is clicked. +We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We use the `useQueryRefHandlers` hook to get access to the `refetch` function which lets us refetch the query when the button is clicked. #### Accessing query ref handlers produced from other hooks `useQueryRefHandlers` is not limited to the `preloadQuery` API and can be used with any hook that produces a `queryRef` such as `useBackgroundQuery` or `useLoadableQuery`. This can be useful in situations where you may need access to the `refetch` and `fetchMore` functions in components where the `queryRef` was passed through deeply. -Let's update our last example back to `useBackgroundQuery` and get access to `refetch` in our `Dog` component instead without needing to pass it from the parent. +Let's update our last example back to `useBackgroundQuery` and get access to `refetch` from `useQueryRefHandlers` in our `Dog` component without passing the `refetch` function from the parent. ```tsx {12,16,18-22,30} function App() { From 4c6877d25b4a171910855255b9acb868a7134fd7 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 22 Jan 2024 21:21:12 -0700 Subject: [PATCH 19/65] Add note about using handlers in both locations --- docs/source/data/suspense.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 8df614cc187..e74d93d800e 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -822,6 +822,12 @@ function Dog({ id, queryRef }: DogProps) { // ... ``` + + +Using the handlers returned from `useQueryRefHandlers` does not prevent you from using the handlers produced by query ref hooks. You can use the handlers in both locations, with or without React transitions to produce the desired result. + + + ## Distinguishing between queries with `queryKey` Apollo Client uses the combination of `query` and `variables` to uniquely identify each query when using Apollo's Suspense data fetching hooks. From b3c64bb3efaa8261b868086af516820f587ca157 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 10:57:24 -0700 Subject: [PATCH 20/65] Update intro paragraph for clarity --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index e74d93d800e..23da0192d8b 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -439,7 +439,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick -`useSuspenseQuery` and `useBackgroundQuery` are useful hooks that will begin loading data as soon as the hook is mounted. But what happens when you'd like to start loading your query in response to a user interaction? With `useSuspenseQuery` and `useBackgroundQuery`, you'd need to update React state in response to the user interaction in order to re-render your component. +`useSuspenseQuery` and `useBackgroundQuery` are useful hooks that will begin loading data as soon as the hook is mounted. But what happens when you'd like to start loading your query in response to a user interaction? With `useSuspenseQuery` and `useBackgroundQuery`, data fetching is bound to the component render. You would have to trigger a rerender to start fetching data for a different set of `variables` (e.g. by changing local component state). Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This is not only more ergonomic, but starts loading the query immediately, providing a nice performance benefit. From 958d6bab4d80236d5d1d11acfb5facfa564ac004 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:07:18 -0700 Subject: [PATCH 21/65] Tweak to what useLoadableQuery returns --- docs/source/data/suspense.mdx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 23da0192d8b..6ee1a04e719 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -443,7 +443,13 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This is not only more ergonomic, but starts loading the query immediately, providing a nice performance benefit. -`useLoadableQuery` returns a function that when called will begin fetching the query with the provided variables. Like `useBackgroundQuery`, you get access to a `queryRef` that is passed to `useReadQuery` to read the data in a child component. When the child component renders before the query has finished loading, the child component suspends. +`useLoadableQuery` returns a both an execution function and `queryRef`. The execution function begins fetching the query when called with the provided variables. Like `useBackgroundQuery`, passing the `queryRef` to `useReadQuery` in a child component suspends the child component until the query finishes loading. + + + +The `queryRef` is `null` until the execution function is called for the first time. You should conditionally render the child component when the query has not yet been loaded. + + Let's update our example to start loading the dog's details as a result of selecting from a dropdown. @@ -487,7 +493,6 @@ function Dog({ queryRef }) { } ``` -> It's important to note that the `queryRef` is `null` until the query loading function is called for the first time. You should conditionally render the child component when the query has not yet been loaded. We begin fetching our `GET_DOG_QUERY` as soon as a new dog is selected rather than waiting for our `Dog` component to re-render. When the `Dog` component renders, it reads data from the `GET_DOG_QUERY`, and if not ready, will suspend. As a result of this change, we've also removed the need to track the selected dog ID as part of React state! From 7be17c12b009d5330282f5f53063a8d61abb58ba Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:14:40 -0700 Subject: [PATCH 22/65] Remove unneeded code tag fr variables --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 6ee1a04e719..6660118bd4d 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -439,7 +439,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick -`useSuspenseQuery` and `useBackgroundQuery` are useful hooks that will begin loading data as soon as the hook is mounted. But what happens when you'd like to start loading your query in response to a user interaction? With `useSuspenseQuery` and `useBackgroundQuery`, data fetching is bound to the component render. You would have to trigger a rerender to start fetching data for a different set of `variables` (e.g. by changing local component state). +`useSuspenseQuery` and `useBackgroundQuery` are useful hooks that will begin loading data as soon as the hook is mounted. But what happens when you'd like to start loading your query in response to a user interaction? With `useSuspenseQuery` and `useBackgroundQuery`, data fetching is bound to the component render. You would have to trigger a rerender to start fetching data for a different set of variables (e.g. by changing local component state). Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This is not only more ergonomic, but starts loading the query immediately, providing a nice performance benefit. From 4cdcb5b954c1f1926955a5d46835b8137992b864 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:16:48 -0700 Subject: [PATCH 23/65] Reword sentence about perf benefit for useLoadableQuery --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 6660118bd4d..1bd9025dd15 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -441,7 +441,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick `useSuspenseQuery` and `useBackgroundQuery` are useful hooks that will begin loading data as soon as the hook is mounted. But what happens when you'd like to start loading your query in response to a user interaction? With `useSuspenseQuery` and `useBackgroundQuery`, data fetching is bound to the component render. You would have to trigger a rerender to start fetching data for a different set of variables (e.g. by changing local component state). -Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This is not only more ergonomic, but starts loading the query immediately, providing a nice performance benefit. +Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This avoids adding additional component state to trigger rerenders and provides a more ergonomic experience. `useLoadableQuery` returns a both an execution function and `queryRef`. The execution function begins fetching the query when called with the provided variables. Like `useBackgroundQuery`, passing the `queryRef` to `useReadQuery` in a child component suspends the child component until the query finishes loading. From b1e423a1d34f233d6f8513798f7e3aa0cfb3f58f Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:18:19 -0700 Subject: [PATCH 24/65] Add missing semicolon in code example Co-authored-by: Lenz Weber-Tronic --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 1bd9025dd15..cc9a7091e60 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -461,7 +461,7 @@ import { function App() { const { data } = useSuspenseQuery(GET_DOGS_QUERY); - const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY) + const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY); return ( <> From d7db9a9ab099a141b0686ecdea4d53778eaf1ae1 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:24:23 -0700 Subject: [PATCH 25/65] Reword summary of code example --- docs/source/data/suspense.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index cc9a7091e60..b814ae80f71 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -493,8 +493,7 @@ function Dog({ queryRef }) { } ``` - -We begin fetching our `GET_DOG_QUERY` as soon as a new dog is selected rather than waiting for our `Dog` component to re-render. When the `Dog` component renders, it reads data from the `GET_DOG_QUERY`, and if not ready, will suspend. As a result of this change, we've also removed the need to track the selected dog ID as part of React state! +We begin fetching our `GET_DOG_QUERY` as soon as a dog is selected by calling the `loadDog` function. When the `Dog` component renders, `useReadQuery` suspends the component while the `GET_DOG_QUERY` loads, then provides `data` to the component. As a result of this change, we've also removed the need to track the selected dog ID as part of React state! From 76db390cdaf8c4fa4d6d0c7a4a0e5e77d362aa67 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:33:47 -0700 Subject: [PATCH 26/65] Add issue link for feedback on query preloading API --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index b814ae80f71..d5f31168bd9 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -505,7 +505,7 @@ Starting with Apollo Client `3.9.0`, it is possible to start loading queries out -This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifically looking for user feedback on the API design choices. The underlying behavior is otherwise fully implemented. If you'd like to provide feedback for this feature before it is stabilized in `3.10.0`, please [open an issue](https://github.com/apollographql/apollo-client/issues/new). +This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifically looking for user feedback on the API design choices. The underlying behavior is otherwise fully implemented. 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. From efa6f2336e925331218fb98246fce3cfffa8c463 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:39:49 -0700 Subject: [PATCH 27/65] Better introduction for createQueryPreloader --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index d5f31168bd9..22a63e20d51 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -509,7 +509,7 @@ This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifica -To begin loading data immediately, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` is given an `ApolloClient` instance as an argument and returns a function that when called, will begin fetching the query. By making `createQueryPreloader` a [curried](https://en.wikipedia.org/wiki/Currying) function, this makes it easy to export your preload function alongside any `ApolloClient` instance you create. +Before you can preload queries, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` is given an `ApolloClient` instance as an argument and returns a function that when called, will begin fetching the query. By making `createQueryPreloader` a [curried](https://en.wikipedia.org/wiki/Currying) function, this makes it easy to export your preload function alongside any `ApolloClient` instance you create. The preload function returns a `queryRef` that can then be passed to `useReadQuery` to read the query data and suspend the component while loading. `useReadQuery` will also ensure that your component containing the preloaded query will be kept up-to-date with any cache updates for that query. From 8577574ab16c6fd564d14f5e69f64fa250085bff Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:40:48 -0700 Subject: [PATCH 28/65] Tweak to export description --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 22a63e20d51..15bf7384109 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -509,7 +509,7 @@ This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifica -Before you can preload queries, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` is given an `ApolloClient` instance as an argument and returns a function that when called, will begin fetching the query. By making `createQueryPreloader` a [curried](https://en.wikipedia.org/wiki/Currying) function, this makes it easy to export your preload function alongside any `ApolloClient` instance you create. +Before you can preload queries, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` is given an `ApolloClient` instance as an argument and returns a function that when called, will begin fetching the query. By making `createQueryPreloader` a [curried](https://en.wikipedia.org/wiki/Currying) function, you can easily export your preload function alongside any `ApolloClient` instance you create. The preload function returns a `queryRef` that can then be passed to `useReadQuery` to read the query data and suspend the component while loading. `useReadQuery` will also ensure that your component containing the preloaded query will be kept up-to-date with any cache updates for that query. From 53a08ee856b03273de4f82a2e7b28c2078f9756c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:41:54 -0700 Subject: [PATCH 29/65] Present tense on useReadQuery description --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 15bf7384109..3d8a6fcff35 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -511,7 +511,7 @@ This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifica Before you can preload queries, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` is given an `ApolloClient` instance as an argument and returns a function that when called, will begin fetching the query. By making `createQueryPreloader` a [curried](https://en.wikipedia.org/wiki/Currying) function, you can easily export your preload function alongside any `ApolloClient` instance you create. -The preload function returns a `queryRef` that can then be passed to `useReadQuery` to read the query data and suspend the component while loading. `useReadQuery` will also ensure that your component containing the preloaded query will be kept up-to-date with any cache updates for that query. +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. Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered. From 974a59f5086bea86c6419101b3a10854b0a983b2 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:48:42 -0700 Subject: [PATCH 30/65] Add note about unmounting preloaded queries --- docs/source/data/suspense.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 3d8a6fcff35..14d8fe8e6f3 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -513,6 +513,12 @@ Before you can preload queries, you first need to create a preload function with 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. + + +It is safe to unmount components that contain preloaded queries. Doing so puts the `queryRef` in a dormant state until the component is mounted again. Any cache updates that may have happened while dormant will be read immediately as if the preloaded query had never been unmounted. + + + Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered. ```tsx {3,6-7,10,33,35} From 2c556f1806bcdb62b8a56c4510f1076d524ffad7 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:52:52 -0700 Subject: [PATCH 31/65] Add comment in code sample about preloadQuery function --- docs/source/data/suspense.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 14d8fe8e6f3..aec84e40495 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -521,12 +521,15 @@ It is safe to unmount components that contain preloaded queries. Doing so puts t Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered. -```tsx {3,6-7,10,33,35} +```tsx {3,9-10,13,36,38} import { // ... createQueryPreloader } from '@apollo/client'; +// This `preloadQuery` function does not have to be created each time you +// need to preload a new query. You may prefer to export this function +// alongside your client instead. const preloadQuery = createQueryPreloader(client); const preloadedQueryRef = preloadQuery(GET_DOGS_QUERY); From 5a40df92c2b947f51a38d05f10b7a16184c9eab0 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:55:28 -0700 Subject: [PATCH 32/65] Tweak to explanation of preloadQuery --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index aec84e40495..daff21b04ad 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -564,7 +564,7 @@ root.render( ); ``` -We begin loading data as soon as our `preloadQuery` function is called. We no longer need to wait for React to render our `` component before our `GET_DOGS_QUERY` begins loading, but still get the benefit of suspense! +We begin loading data as soon as our `preloadQuery` function is called rather than waiting for React to render our `` component. Because the `preloadedQueryRef` is passed to `useReadQuery` in our `App` component, we still get the benefit of suspense and cache updates! #### Usage with data loading routers From 892db6a10f9623488f080187925dbc9544c1fa2e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:58:16 -0700 Subject: [PATCH 33/65] Remove redudancy for data loading routers in intro paragraph --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index daff21b04ad..87f80440b3c 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -568,7 +568,7 @@ We begin loading data as soon as our `preloadQuery` function is called rather th #### Usage with data loading routers -Popular routers such as [React Router](https://reactrouter.com/en/main) and [TanStack Router](https://tanstack.com/router) include APIs to start loading data before the route component renders (e.g. such as the [`loader` function](https://reactrouter.com/en/main/route/route#loader) from React Router). These APIs have the benefit that they can begin loading data in parallel without the need to wait for the route components to render. This is especially useful for nested routes where a parent route might otherwise suspend and create request waterfalls for child routes. +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. The `preloadQuery` API pairs nicely with these router APIs as it lets you take advantage of the optimizations these routers provide without sacrificing the ability to respond to cache updates in your route components. From a754c6c24c8de69e8c324fc1347db78b151376b4 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 11:59:36 -0700 Subject: [PATCH 34/65] Tweak to sentence about preloadQuery with router apis --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 87f80440b3c..452428b2e14 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -570,7 +570,7 @@ We begin loading data as soon as our `preloadQuery` function is called rather th 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. -The `preloadQuery` API pairs nicely with these router APIs as it lets you take advantage of the optimizations these routers provide without sacrificing the ability to respond to cache updates in your route components. +The `preloadQuery` API 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. Let's update our example using React Router's `loader` function to begin loading data when we transition to our route. From 41c794bfbf76205b07d151f22b7d97ffc451e4f5 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:09:56 -0700 Subject: [PATCH 35/65] Adjust paragraph for description on preloading with react router --- docs/source/data/suspense.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 452428b2e14..ccc592276df 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -593,11 +593,11 @@ export function RouteComponent() { > The `loader` function is available in React Router versions 6.4 and above. -We load our query as soon as React Router calls our `loader` function. This starts fetching before our route component is rendered. When our route component renders, we can get access to the `queryRef` created by our `preloadQuery` function via the `useLoaderData` hook, which is then passed to `useReadQuery` to read the data. We get the benefit of loading our data early in the routing lifecycle, while our route component has the ability to update itself when the cache is updated! +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! -The `preloadQuery` API 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/). +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/). From 97bb5ba0a83b1a5f9fe37ac10ddea8023484af02 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:12:57 -0700 Subject: [PATCH 36/65] Use present tense --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index ccc592276df..a105aa0035c 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -626,7 +626,7 @@ export function RouteComponent() { } ``` -This instructs React Router to wait for the query to finish loading before the route transitions. When the route transitions after the promise resolves, the data will be rendered immediately without the need to show a loading fallback in the route component. +This instructs React Router to wait for the query to finish loading before the route transitions. When the route transitions after the promise resolves, the data is rendered immediately without the need to show a loading fallback in the route component. #### Why prevent access to `data` in `toPromise`? From ea04c9ece53dfb4454500e4a8b478181ebb74d8d Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:14:00 -0700 Subject: [PATCH 37/65] Remove This is because --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index a105aa0035c..b829907a5e3 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -630,7 +630,7 @@ This instructs React Router to wait for the query to finish loading before the r #### Why prevent access to `data` in `toPromise`? -You may be wondering why we resolve `toPromise` with the `queryRef` itself, rather than the data loaded from the query. This is because we want to encourage you to leverage `useReadQuery` to avoid missing out on cache updates for your query. If `data` were available, it would be tempting to consume it in your `loader` functions and expose it to your route components. Doing so means missing out on cache updates. +You may be wondering why we resolve `toPromise` with the `queryRef` itself, rather than the data loaded from the query. We want to encourage you to leverage `useReadQuery` to avoid missing out on cache updates for your query. If `data` were available, it would be tempting to consume it in your `loader` functions and expose it to your route components. Doing so means missing out on cache updates. If you need access to raw query data in your `loader` functions, use [`client.query()`](../api/core/ApolloClient#query) directly. From 9df38c69c3a2c1aab8e82955fc2e9731929b0fe5 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:19:12 -0700 Subject: [PATCH 38/65] Tweak to verbage for query preloading and refetching --- docs/source/data/suspense.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index b829907a5e3..8e27c8a0f25 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -716,11 +716,11 @@ In this example, our `App` component renders a `Dog` component that fetches a si #### Usage with query preloading -When loading queries [outside React](#initiating-queries-outside-react), the `preloadQuery` function returns a `queryRef` with no access to `refetch` or `fetchMore` functions. This presents a challenge if you need to refresh or paginate on the data returned by the query ref. +When loading queries [outside React](#initiating-queries-outside-react), the `preloadQuery` function returns a `queryRef` with no access to `refetch` or `fetchMore` functions. This presents a challenge when you need to refetch or paginate the preloaded query. You can gain access to `refetch` and `fetchMore` functions by using the `useQueryRefHandlers` hook. This hook integrates with React transitions, giving you the ability to refetch or paginate without showing the loading fallback. -Let's update our example to preload our `GET_BREEDS_QUERY` outside React and utilize `useQueryRefHandlers` to refetch our query. +Let's update our example to preload our `GET_BREEDS_QUERY` outside React and use the `useQueryRefHandlers` hook to refetch our query. ```tsx {4,7-8,12} // ... From 0238b0d29c0c491794ff7b50f9efe3f76935122a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:19:18 -0700 Subject: [PATCH 39/65] Remove unneeded context from prefetch refetch code example --- docs/source/data/suspense.mdx | 38 ++--------------------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 8e27c8a0f25..dcc4b46d8dc 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -722,14 +722,13 @@ You can gain access to `refetch` and `fetchMore` functions by using the `useQuer Let's update our example to preload our `GET_BREEDS_QUERY` outside React and use the `useQueryRefHandlers` hook to refetch our query. -```tsx {4,7-8,12} +```tsx {4,7,11} // ... import { // ... useQueryRefHandlers, } from "@apollo/client"; -const preloadQuery = createQueryPreloader(client); const queryRef = preloadQuery(GET_BREEDS_QUERY); function App() { @@ -753,40 +752,7 @@ function App() { ); } -function Dog({ - id, - isPending, - onRefetch, -}: DogProps) { - const { data } = useSuspenseQuery(GET_DOG_QUERY, { - variables: { id }, - }); - - return ( - <> - Name: {data.dog.name} - Loading breeds...}> - - - - - ); -} - -function Breeds({ isPending }: BreedsProps) { - const { data } = useReadQuery(queryRef); - - return data.breeds.map(({ characteristics }) => - characteristics.map((characteristic) => ( -
- {characteristic} -
- )) - ); -} +// ... ``` We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We use the `useQueryRefHandlers` hook to get access to the `refetch` function which lets us refetch the query when the button is clicked. From 974133b5d79e2aa04aab6a8f8e1f10e8998de9dc Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:20:24 -0700 Subject: [PATCH 40/65] Use present tense --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index dcc4b46d8dc..cd4c2429197 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -755,7 +755,7 @@ function App() { // ... ``` -We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We use the `useQueryRefHandlers` hook to get access to the `refetch` function which lets us refetch the query when the button is clicked. +We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We use the `useQueryRefHandlers` hook to get the `refetch` function which refetches the query when the button is clicked. #### Accessing query ref handlers produced from other hooks From 4c541ac158083d6899c646690e29276ee278b316 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:23:10 -0700 Subject: [PATCH 41/65] Swap where useTransition is used --- docs/source/data/suspense.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index cd4c2429197..e13d52c9e89 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -763,7 +763,7 @@ We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` fun Let's update our last example back to `useBackgroundQuery` and get access to `refetch` from `useQueryRefHandlers` in our `Dog` component without passing the `refetch` function from the parent. -```tsx {12,16,18-22,30} +```tsx {15,16,18-22,30} function App() { const [queryRef] = useBackgroundQuery(GET_BREEDS_QUERY); @@ -775,10 +775,10 @@ function App() { } function Dog({ id, queryRef }: DogProps) { - const [isPending, startTransition] = useTransition(); const { data } = useSuspenseQuery(GET_DOG_QUERY, { variables: { id }, }); + const [isPending, startTransition] = useTransition(); const { refetch } = useQueryRefHandlers(queryRef); function handleRefetch() { From 0f9f34a480c9e05bc6152dcb72b7af22e602e316 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:23:43 -0700 Subject: [PATCH 42/65] Present tense --- docs/source/data/suspense.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index e13d52c9e89..a332922a7ca 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -759,9 +759,9 @@ We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` fun #### Accessing query ref handlers produced from other hooks -`useQueryRefHandlers` is not limited to the `preloadQuery` API and can be used with any hook that produces a `queryRef` such as `useBackgroundQuery` or `useLoadableQuery`. This can be useful in situations where you may need access to the `refetch` and `fetchMore` functions in components where the `queryRef` was passed through deeply. +`useQueryRefHandlers` is not limited to the `preloadQuery` function and can be used with any hook that produces a `queryRef` such as `useBackgroundQuery` or `useLoadableQuery`. This is useful in situations where you need access to the `refetch` and `fetchMore` functions in components where the `queryRef` is passed through deeply. -Let's update our last example back to `useBackgroundQuery` and get access to `refetch` from `useQueryRefHandlers` in our `Dog` component without passing the `refetch` function from the parent. +Let's update our last example back to `useBackgroundQuery` and get the `refetch` function from the `useQueryRefHandlers` hook in the `Dog` component. ```tsx {15,16,18-22,30} function App() { From 87ed45a3a33ee059181b6414f08b3cd58566078b Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 12:38:32 -0700 Subject: [PATCH 43/65] Rename Querying in response to Fetching in response --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index a332922a7ca..3a15a1f4a0d 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -435,7 +435,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick -### Querying in response to user interaction +### Fetching in response to user interaction From aa7c5d92d0f26118e906742566f94c78e294fe6c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 24 Jan 2024 17:40:09 -0700 Subject: [PATCH 44/65] Strip trailing whitespace --- docs/source/data/suspense.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 3a15a1f4a0d..9ad3b947386 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -527,9 +527,9 @@ import { createQueryPreloader } from '@apollo/client'; -// This `preloadQuery` function does not have to be created each time you -// need to preload a new query. You may prefer to export this function -// alongside your client instead. +// This `preloadQuery` function does not have to be created each time you +// need to preload a new query. You may prefer to export this function +// alongside your client instead. const preloadQuery = createQueryPreloader(client); const preloadedQueryRef = preloadQuery(GET_DOGS_QUERY); @@ -598,7 +598,7 @@ React Router calls the `loader` function which we use to begin loading the `GET_ 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/). - + #### Preventing route transitions until the query is loaded @@ -612,7 +612,7 @@ export async function loader() { return queryRef; } -// You may also return the promise directly from loader. +// You may also return the promise directly from loader. // This is equivalent to the above. export async function loader() { return preloadQuery(GET_DOGS_QUERY).toPromise(); @@ -729,7 +729,7 @@ import { useQueryRefHandlers, } from "@apollo/client"; -const queryRef = preloadQuery(GET_BREEDS_QUERY); +const queryRef = preloadQuery(GET_BREEDS_QUERY); function App() { const [isPending, startTransition] = useTransition(); From 4a4b1ba85511e4e5a9ec870646495c7f13837ffe Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 10:09:48 -0700 Subject: [PATCH 45/65] Update notes about experimental features --- docs/source/data/suspense.mdx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 9ad3b947386..961b50fe35e 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -505,7 +505,7 @@ Starting with Apollo Client `3.9.0`, it is possible to start loading queries out -This API is experimental in `3.9.0` and may change in `3.10.0`. We are specifically looking for user feedback on the API design choices. The underlying behavior is otherwise fully implemented. 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. +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. @@ -628,6 +628,12 @@ export function RouteComponent() { This instructs React Router to wait for the query to finish loading before the route transitions. When the route transitions after the promise resolves, the data is rendered immediately without the need to show a loading fallback in the route component. + + +`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. + + + #### Why prevent access to `data` in `toPromise`? You may be wondering why we resolve `toPromise` with the `queryRef` itself, rather than the data loaded from the query. We want to encourage you to leverage `useReadQuery` to avoid missing out on cache updates for your query. If `data` were available, it would be tempting to consume it in your `loader` functions and expose it to your route components. Doing so means missing out on cache updates. From fdcd3949051d97eb10a97d518937bbcf878c2c43 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:28:16 -0700 Subject: [PATCH 46/65] Reword intro paragraph to `useLoadableQuery` Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 961b50fe35e..00e45df6ecd 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -439,7 +439,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick
-`useSuspenseQuery` and `useBackgroundQuery` are useful hooks that will begin loading data as soon as the hook is mounted. But what happens when you'd like to start loading your query in response to a user interaction? With `useSuspenseQuery` and `useBackgroundQuery`, data fetching is bound to the component render. You would have to trigger a rerender to start fetching data for a different set of variables (e.g. by changing local component state). +`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. Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This avoids adding additional component state to trigger rerenders and provides a more ergonomic experience. From 864ff7fae37028b430cfeb2f1cf3a8b6ea0cabb4 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:29:03 -0700 Subject: [PATCH 47/65] Remove unnecessary detail on `useLoadableQuery` Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 00e45df6ecd..890d8c3aa49 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -441,7 +441,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick `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. -Starting with Apollo Client `3.9.0`, you can use `useLoadableQuery` to start loading data in response to user interaction. This avoids adding additional component state to trigger rerenders and provides a more ergonomic experience. +Available as of Apollo Client `3.9.0`, the `useLoadableQuery` hook initiates a network request in response to user interaction. `useLoadableQuery` returns a both an execution function and `queryRef`. The execution function begins fetching the query when called with the provided variables. Like `useBackgroundQuery`, passing the `queryRef` to `useReadQuery` in a child component suspends the child component until the query finishes loading. From 3503883836d51c5534a7d1d3cb7df2a6a4ac33d4 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:29:52 -0700 Subject: [PATCH 48/65] Fix typo and better align verbiage Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 890d8c3aa49..f634736fe49 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -443,7 +443,7 @@ The `useBackgroundQuery` hook used in a parent component is responsible for kick Available as of Apollo Client `3.9.0`, the `useLoadableQuery` hook initiates a network request in response to user interaction. -`useLoadableQuery` returns a both an execution function and `queryRef`. The execution function begins fetching the query when called with the provided variables. Like `useBackgroundQuery`, passing the `queryRef` to `useReadQuery` in a child component suspends the child component until the query finishes loading. +`useLoadableQuery` returns both an execution function and a `queryRef`. The execution function initiates a network request when called with the provided variables. Like `useBackgroundQuery`, passing the `queryRef` to `useReadQuery` in a child component suspends the child component until the query finishes loading. From f701bb6ec9fed34e13c4c4b1a5dfe311dd885406 Mon Sep 17 00:00:00 2001 From: jerelmiller Date: Fri, 26 Jan 2024 22:30:42 +0000 Subject: [PATCH 49/65] Clean up Prettier, Size-limit, and Api-Extractor --- .size-limits.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.size-limits.json b/.size-limits.json index 395aea47c38..96d031aaf5d 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,4 +1,4 @@ { "dist/apollo-client.min.cjs": 37930, - "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 31972 + "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 31974 } From 7343d6c5027316b3896a07027a8ab37dd562386e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:31:09 -0700 Subject: [PATCH 50/65] Remove "you" for conditional render section Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index f634736fe49..288e388185d 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -447,7 +447,7 @@ Available as of Apollo Client `3.9.0`, the `useLoadableQuery` hook initiates a n -The `queryRef` is `null` until the execution function is called for the first time. You should conditionally render the child component when the query has not yet been loaded. +The `queryRef` is `null` until the execution function is called for the first time. For this reason, any child components attempting to read data using the `queryRef` should be conditionally rendered. From 680714d7aa6105baec30b4ff96a1a353d4f7571e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:35:07 -0700 Subject: [PATCH 51/65] Reword summary for loading dog --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 288e388185d..0033eef0c2d 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -493,7 +493,7 @@ function Dog({ queryRef }) { } ``` -We begin fetching our `GET_DOG_QUERY` as soon as a dog is selected by calling the `loadDog` function. When the `Dog` component renders, `useReadQuery` suspends the component while the `GET_DOG_QUERY` loads, then provides `data` to the component. As a result of this change, we've also removed the need to track the selected dog ID as part of React state! +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! From d457cad1c0c656c57a1a2de526f1ca73a2c2d149 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:37:32 -0700 Subject: [PATCH 52/65] Fix wrong API signature in code example Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 0033eef0c2d..44948ff719c 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -461,7 +461,7 @@ import { function App() { const { data } = useSuspenseQuery(GET_DOGS_QUERY); - const [queryRef, loadDog] = useLoadableQuery(GET_DOG_QUERY); + const [loadDog, queryRef] = useLoadableQuery(GET_DOG_QUERY); return ( <> From f3d9fde6054bd70d02b8944d2ed4125748cca095 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:40:28 -0700 Subject: [PATCH 53/65] Add prop type to code example Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 44948ff719c..e989ecf86ba 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -481,7 +481,7 @@ function App() { ); } -function Dog({ queryRef }) { +function Dog({ queryRef }: DogProps) { const { data } = useReadQuery(queryRef) return ( From f7c1de184bba1544f9d21448afe0624da0ced6af Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:41:09 -0700 Subject: [PATCH 54/65] Reword intro to preloading feature Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index e989ecf86ba..e351f207b66 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -501,7 +501,7 @@ We begin fetching our `GET_DOG_QUERY` by calling the `loadDog` function inside o -Starting with Apollo Client `3.9.0`, it is possible to start loading queries outside React. This avoids the need to wait for React to render your components before the query begins loading, providing a nice performance benefit. +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. From 08c845deacfffd3ea6a952735c18643605605fbe Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:43:17 -0700 Subject: [PATCH 55/65] Shorten reference to preloadQuery --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index e351f207b66..b417aca2f0d 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -570,7 +570,7 @@ We begin loading data as soon as our `preloadQuery` function is called rather th 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. -The `preloadQuery` API 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. +`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. Let's update our example using React Router's `loader` function to begin loading data when we transition to our route. From 4176bfe3c80496b1c6b70ce113e5b83575f4ffde Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:45:26 -0700 Subject: [PATCH 56/65] Split intro to toPromise into 2 paragraphs Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index b417aca2f0d..1d0891b9ef7 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -603,7 +603,11 @@ The `preloadQuery` function only works with client-side routing. The `queryRef` #### Preventing route transitions until the query is loaded -By default, `preloadQuery` works similar to a [deferred loader](https://reactrouter.com/en/main/guides/deferred) in that routes will transition immediately and suspend with `useReadQuery` until the query is loaded. You may instead want to prevent the route from transitioning until the data is fully loaded. Use the `toPromise` method on the `queryRef` to get a promise that resolves when the query is loaded. This promise resolves with the `queryRef` itself, making it easy to use with hooks such as `useLoaderData`. +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. + +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`. + +Here's an example: ```ts export async function loader() { From b1c44cf1f2c99aaaa2762998dba6ae5e8bb63ebe Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:51:39 -0700 Subject: [PATCH 57/65] Reword section about unmounting preloaded query Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 1d0891b9ef7..7a31035ec7e 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -515,7 +515,7 @@ The preload function returns a `queryRef` that is passed to `useReadQuery` to re -It is safe to unmount components that contain preloaded queries. Doing so puts the `queryRef` in a dormant state until the component is mounted again. Any cache updates that may have happened while dormant will be read immediately as if the preloaded query had never been unmounted. +Unmounting components that contain preloaded queries is safe and puts the `queryRef` in a dormant state. Once the component re-mounts, any cache updates that occurred in the interim are read immediately as if the preloaded query had never been unmounted. From c9a1c2436f0992c86af6024a21fab14720e833e0 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:53:40 -0700 Subject: [PATCH 58/65] Reword section about `useQueryRefHandlers` Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 7a31035ec7e..074ab42d9f4 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -769,7 +769,7 @@ We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` fun #### Accessing query ref handlers produced from other hooks -`useQueryRefHandlers` is not limited to the `preloadQuery` function and can be used with any hook that produces a `queryRef` such as `useBackgroundQuery` or `useLoadableQuery`. This is useful in situations where you need access to the `refetch` and `fetchMore` functions in components where the `queryRef` is passed through deeply. +`useQueryRefHandlers` can also be used in combination with any hook that returns a `queryRef`, such as `useBackgroundQuery` or `useLoadableQuery`. This is useful when you need access to the `refetch` and `fetchMore` functions in components where the `queryRef` is passed through deeply. Let's update our last example back to `useBackgroundQuery` and get the `refetch` function from the `useQueryRefHandlers` hook in the `Dog` component. From d6ff31183dd866703a52696680d2a7d05faec285 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 15:57:51 -0700 Subject: [PATCH 59/65] Reword description for example Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 074ab42d9f4..020962e4100 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -771,7 +771,7 @@ We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` fun `useQueryRefHandlers` can also be used in combination with any hook that returns a `queryRef`, such as `useBackgroundQuery` or `useLoadableQuery`. This is useful when you need access to the `refetch` and `fetchMore` functions in components where the `queryRef` is passed through deeply. -Let's update our last example back to `useBackgroundQuery` and get the `refetch` function from the `useQueryRefHandlers` hook in the `Dog` component. +Let's update our example to use `useBackgroundQuery` again and see how we can access a `refetch` function in our `Dog` component using `useQueryRefHandlers`: ```tsx {15,16,18-22,30} function App() { From 5966ad2df1557ab7ebb81285fbf06a2837bde18c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 16:00:30 -0700 Subject: [PATCH 60/65] Use more technical language for note --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 020962e4100..26bb07104b6 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -515,7 +515,7 @@ The preload function returns a `queryRef` that is passed to `useReadQuery` to re -Unmounting components that contain preloaded queries is safe and puts the `queryRef` in a dormant state. Once the component re-mounts, any cache updates that occurred in the interim are read immediately as if the preloaded query had never been unmounted. +Unmounting components that contain preloaded queries is safe and diposes of the `queryRef`. When the component re-mounts, `useReadQuery` automatically resubscribes to the `queryRef` and any cache updates that occurred in the interim are read immediately as if the preloaded query had never been unmounted. From b76cd2578d7c96d9dba0e54354d71dcbed80051a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 16:02:46 -0700 Subject: [PATCH 61/65] More explicit about queryRef and refetch Co-authored-by: Alessia Bellisario --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index 26bb07104b6..b5872aa672f 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -765,7 +765,7 @@ function App() { // ... ``` -We begin loading `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We use the `useQueryRefHandlers` hook to get the `refetch` function which refetches the query when the button is clicked. +We begin loading our `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We pass the `queryRef` returned from `preloadQuery` to the `useQueryRefHandlers` hook which provides us with a `refetch` function we can use to refetch the query when the button is clicked. #### Accessing query ref handlers produced from other hooks From 32076535350f6c0f7c582c2e054919579db9624b Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 16:17:21 -0700 Subject: [PATCH 62/65] Remove part about currying --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index b5872aa672f..ef19986e22e 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -509,7 +509,7 @@ This feature is in [alpha stage](https://www.apollographql.com/docs/resources/pr -Before you can preload queries, you first need to create a preload function with `createQueryPreloader`. `createQueryPreloader` is given an `ApolloClient` instance as an argument and returns a function that when called, will begin fetching the query. By making `createQueryPreloader` a [curried](https://en.wikipedia.org/wiki/Currying) function, you can easily export your preload function alongside any `ApolloClient` instance you create. +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. 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. From a135979ae5804a0d6c8dd43ba204a560c3d98561 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 16:23:48 -0700 Subject: [PATCH 63/65] Move note about exporting to tip component --- docs/source/data/suspense.mdx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index ef19986e22e..f60fdcc401e 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -501,23 +501,24 @@ We begin fetching our `GET_DOG_QUERY` by calling the `loadDog` function inside o -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. - 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. +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. + 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. -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. + - +Consider exporting your preload function along with your `ApolloClient` instance. This allows you to import that function directly without having to pass around your `ApolloClient` instance each time you preload a query. -Unmounting components that contain preloaded queries is safe and diposes of the `queryRef`. When the component re-mounts, `useReadQuery` automatically resubscribes to the `queryRef` and any cache updates that occurred in the interim are read immediately as if the preloaded query had never been unmounted. + + +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. - Let's update our example to start loading the `GET_DOGS_QUERY` before our app is rendered. @@ -566,6 +567,12 @@ root.render( We begin loading data as soon as our `preloadQuery` function is called rather than waiting for React to render our `` component. Because the `preloadedQueryRef` is passed to `useReadQuery` in our `App` component, we still get the benefit of suspense and cache updates! + + +Unmounting components that contain preloaded queries is safe and diposes of the `queryRef`. When the component re-mounts, `useReadQuery` automatically resubscribes to the `queryRef` and any cache updates that occurred in the interim are read immediately as if the preloaded query had never been unmounted. + + + #### Usage with data loading routers 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. From 820742a43056e6464cdb56fcb371461085a4b9a8 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 16:26:47 -0700 Subject: [PATCH 64/65] Tweak to headline --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index f60fdcc401e..e93e739242f 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -774,7 +774,7 @@ function App() { We begin loading our `GET_BREEDS_QUERY` outside of React with the `preloadQuery` function. We pass the `queryRef` returned from `preloadQuery` to the `useQueryRefHandlers` hook which provides us with a `refetch` function we can use to refetch the query when the button is clicked. -#### Accessing query ref handlers produced from other hooks +#### Using `useQueryRefHandlers` with query refs produced from other Suspense hooks `useQueryRefHandlers` can also be used in combination with any hook that returns a `queryRef`, such as `useBackgroundQuery` or `useLoadableQuery`. This is useful when you need access to the `refetch` and `fetchMore` functions in components where the `queryRef` is passed through deeply. From c2362191d317fd56238472bf33c70519dff2ebfd Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 16:40:01 -0700 Subject: [PATCH 65/65] Fix typo --- docs/source/data/suspense.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index e93e739242f..056b601f44a 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -569,7 +569,7 @@ We begin loading data as soon as our `preloadQuery` function is called rather th -Unmounting components that contain preloaded queries is safe and diposes of the `queryRef`. When the component re-mounts, `useReadQuery` automatically resubscribes to the `queryRef` and any cache updates that occurred in the interim are read immediately as if the preloaded query had never been unmounted. +Unmounting components that contain preloaded queries is safe and disposes of the `queryRef`. When the component re-mounts, `useReadQuery` automatically resubscribes to the `queryRef` and any cache updates that occurred in the interim are read immediately as if the preloaded query had never been unmounted.