From e9cb1db475b624f257fc04eb039e363d41a1d0bd Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Thu, 23 May 2024 14:06:29 +0200 Subject: [PATCH 1/5] update README --- .../experimental-nextjs-app-support/README.md | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/packages/experimental-nextjs-app-support/README.md b/packages/experimental-nextjs-app-support/README.md index 1eadf21a..12a34294 100644 --- a/packages/experimental-nextjs-app-support/README.md +++ b/packages/experimental-nextjs-app-support/README.md @@ -9,8 +9,8 @@ > This cannot be addressed from our side, but would need API changes in Next.js or React itself. > If you do not use suspense in your application, this will not be a problem to you. -| ☑️ Apollo Client User Survey | -| :----- | +| ☑️ Apollo Client User Survey | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | What do you like best about Apollo Client? What needs to be improved? Please tell us by taking a [one-minute survey](https://docs.google.com/forms/d/e/1FAIpQLSczNDXfJne3ZUOXjk9Ursm9JYvhTh1_nFTDfdq3XBAFWCzplQ/viewform?usp=pp_url&entry.1170701325=Apollo+Client&entry.204965213=Readme). Your responses will help us understand Apollo Client usage and allow us to serve you better. | ## Detailed technical breakdown @@ -57,7 +57,7 @@ import { InMemoryCache, } from "@apollo/experimental-nextjs-app-support"; -export const { getClient } = registerApolloClient(() => { +export const { getClient, query, PreloadQuery } = registerApolloClient(() => { return new ApolloClient({ cache: new InMemoryCache(), link: new HttpLink({ @@ -75,9 +75,13 @@ You can then use that `getClient` function in your server components: ```js const { data } = await getClient().query({ query: userQuery }); +// `query` is a shortcut for `getClient().query` +const { data } = await query({ query: userQuery }); ``` -### In SSR +For a description of `PreloadQuery`, see [Preloading data in RSC for usage in Client Components](#...) + +### In Client Components and streaming SSR If you use the `app` directory, each Client Component _will_ be SSR-rendered for the initial request. So you will need to use this package. @@ -154,6 +158,60 @@ export default function RootLayout({ If you want to make the most of the streaming SSR features offered by React & the Next.js App Router, consider using the [`useSuspenseQuery`](https://www.apollographql.com/docs/react/api/react/hooks-experimental/#using-usesuspensequery_experimental) and [`useFragment`](https://www.apollographql.com/docs/react/api/react/hooks-experimental/#using-usefragment_experimental) hooks. +### Preloading data in RSC for usage in Client Components + +You can also preload data in RSC to populate the cache of your Client Components. + +For that, follow the setup steps for both RSC and Client Components as laid out in the last two paragraphs. + +Then you can use the `PreloadQuery` component in your React Server Components: + +```jsx + + loading}> + + + +``` + +> The `Suspense` boundary here is optional. + +This example will fetch your query in RSC, and then transport the data into your Client Component cache. +Before the child `ClientComponent` in the example renders, a "simulated network request" for this query is started in your Client Components. +That way, if you repeat the query in your Client Component using `useSuspenseQuery` (or even `useQuery`!), it will wait for the network request in your Server Component to finish instead of making it's own network request. + +> Keep in mind that we recommend not to mix "client data" and "RSC data". Data fetched this way should be considerd "client data" and never be referenced in your Server Components. In fact, `PreloadQuery` will create a separate `ApolloClient` instance from the instance normally used in RSC, to prevent mixing data. + +#### Usage with `useReadQuery`. + +You can also use this approach in combination with `useReadQuery` on the client. For that, you can use this "render prop" approach to get a transportable `QueryRef` that you can pass down into your Client Components: + +```jsx + + {(queryRef) => ( + loading}> + + + )} + +``` + +Inside of `ClientChild`, you could then call `useReadQuery` with the `queryRef` prop. The `Suspense` boundary in the example is optional. + +#### Caveat + +Keep in mind that this will look like a "new network request" to your Client Component, so make sure that the data you pass from your Server Components is not outdated, e.g. because of other caching layers you might be using. + ### Resetting singletons between tests. This package uses some singleton instances on the Browser side - if you are writing tests, you must reset them between tests. From 4826fdf79d107d7f27243066815b6dba4599d5ba Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Thu, 23 May 2024 14:10:32 +0200 Subject: [PATCH 2/5] anchor --- packages/experimental-nextjs-app-support/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/experimental-nextjs-app-support/README.md b/packages/experimental-nextjs-app-support/README.md index 12a34294..36c8fdf9 100644 --- a/packages/experimental-nextjs-app-support/README.md +++ b/packages/experimental-nextjs-app-support/README.md @@ -79,7 +79,7 @@ const { data } = await getClient().query({ query: userQuery }); const { data } = await query({ query: userQuery }); ``` -For a description of `PreloadQuery`, see [Preloading data in RSC for usage in Client Components](#...) +For a description of `PreloadQuery`, see [Preloading data in RSC for usage in Client Components](#preloading-data-in-rsc-for-usage-in-client-components) ### In Client Components and streaming SSR From fd00faf8fa01cc016a633194336d19defac01523 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Wed, 29 May 2024 11:07:29 +0200 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Jerel Miller --- .../experimental-nextjs-app-support/README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/experimental-nextjs-app-support/README.md b/packages/experimental-nextjs-app-support/README.md index 36c8fdf9..a7b92fab 100644 --- a/packages/experimental-nextjs-app-support/README.md +++ b/packages/experimental-nextjs-app-support/README.md @@ -160,11 +160,9 @@ If you want to make the most of the streaming SSR features offered by React & th ### Preloading data in RSC for usage in Client Components -You can also preload data in RSC to populate the cache of your Client Components. +Starting with version 0.11, you can preload data in RSC to populate the cache of your Client Components. -For that, follow the setup steps for both RSC and Client Components as laid out in the last two paragraphs. - -Then you can use the `PreloadQuery` component in your React Server Components: +For that, follow the setup steps for both RSC and Client Components as laid out in the last two paragraphs. Then you can use the `PreloadQuery` component in your React Server Components: ```jsx The `Suspense` boundary here is optional. -This example will fetch your query in RSC, and then transport the data into your Client Component cache. -Before the child `ClientComponent` in the example renders, a "simulated network request" for this query is started in your Client Components. +This example will fetch a query in RSC, and then transport the data into the Client Component cache. +Before the child `ClientChild` in the example renders, a "simulated network request" for this query is started in your Client Components. That way, if you repeat the query in your Client Component using `useSuspenseQuery` (or even `useQuery`!), it will wait for the network request in your Server Component to finish instead of making it's own network request. -> Keep in mind that we recommend not to mix "client data" and "RSC data". Data fetched this way should be considerd "client data" and never be referenced in your Server Components. In fact, `PreloadQuery` will create a separate `ApolloClient` instance from the instance normally used in RSC, to prevent mixing data. +> [!IMPORTANT] +> Keep in mind that we don't recommend mixing data between Client Components and Server Components. Data fetched this way should be considered client data and never be referenced in your Server Components. `PreloadQuery` prevents mixing server data and client data by creating a separate `ApolloClient` instance using the `makeClient` function passed into `registerApolloClient`. #### Usage with `useReadQuery`. -You can also use this approach in combination with `useReadQuery` on the client. For that, you can use this "render prop" approach to get a transportable `QueryRef` that you can pass down into your Client Components: +You can also use this approach in combination with `useReadQuery` in Client Components. Use the render prop approach to get a `QueryRef` that you can pass to your Client Component: ```jsx Date: Wed, 29 May 2024 11:30:15 +0200 Subject: [PATCH 4/5] review feedback --- .../experimental-nextjs-app-support/README.md | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/experimental-nextjs-app-support/README.md b/packages/experimental-nextjs-app-support/README.md index a7b92fab..b41cbfc8 100644 --- a/packages/experimental-nextjs-app-support/README.md +++ b/packages/experimental-nextjs-app-support/README.md @@ -177,7 +177,23 @@ For that, follow the setup steps for both RSC and Client Components as laid out ``` -> The `Suspense` boundary here is optional. +And you can use `useSuspenseQuery` in your `ClientChild` component with the same QUERY: + +```jsx +"use client"; + +import { useSuspenseQuery } from "@apollo/client"; +// ... + +export function ClientChild() { + const { data } = useSuspenseQuery(QUERY); + return
...
; +} +``` + +> [!TIP] +> The `Suspense` boundary here is optional and only for demonstration purposes to show that something suspenseful is going on. +> Place `Suspense` boundaries at meaningful places in your UI, where they give your users the best user experience. This example will fetch a query in RSC, and then transport the data into the Client Component cache. Before the child `ClientChild` in the example renders, a "simulated network request" for this query is started in your Client Components. @@ -205,7 +221,23 @@ You can also use this approach in combination with `useReadQuery` in Client Comp
``` -Inside of `ClientChild`, you could then call `useReadQuery` with the `queryRef` prop. The `Suspense` boundary in the example is optional. +Inside of `ClientChild`, you could then call `useReadQuery` with the `queryRef` prop. + +```jsx +"use client"; + +import { useQueryRefHandlers, useReadQuery, QueryRef } from "@apollo/client"; + +export function ClientChild({ queryRef }: { queryRef: QueryRef }) { + const { refetch } = useQueryRefHandlers(queryRef); + const { data } = useReadQuery(queryRef); + return
...
; +} +``` + +> [!TIP] +> The `Suspense` boundary here is optional and only for demonstration purposes to show that something suspenseful is going on. +> Place `Suspense` boundaries at meaningful places in your UI, where they give your users the best user experience. #### Caveat From 2528e36dd178dc9bda003a26605deea553936e8f Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Wed, 29 May 2024 11:40:22 +0200 Subject: [PATCH 5/5] clarification --- packages/experimental-nextjs-app-support/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/experimental-nextjs-app-support/README.md b/packages/experimental-nextjs-app-support/README.md index b41cbfc8..940d941e 100644 --- a/packages/experimental-nextjs-app-support/README.md +++ b/packages/experimental-nextjs-app-support/README.md @@ -241,7 +241,7 @@ export function ClientChild({ queryRef }: { queryRef: QueryRef }) { #### Caveat -Keep in mind that this will look like a "new network request" to your Client Component, so make sure that the data you pass from your Server Components is not outdated, e.g. because of other caching layers you might be using. +Keep in mind that this will look like a "current network request" to your Client Component and as such will update data that is already in your Client Component cache, so make sure that the data you pass from your Server Components is not outdated, e.g. because of other caching layers you might be using, like the Next.js fetch cache. ### Resetting singletons between tests.