From 2964a13c08e5644b8484a94ede12e02cdf85bce0 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 26 Jan 2024 16:29:33 -0700 Subject: [PATCH] Document new React APIs in code - Part 2 of 2 (#11523) --- .api-reports/api-report-react.md | 16 ++--- .api-reports/api-report-react_hooks.md | 14 ++--- .api-reports/api-report-react_internal.md | 6 +- .api-reports/api-report.md | 16 ++--- .prettierignore | 2 + .../Overrides/UseLoadableQueryResult.js | 58 +++++++++++++++++++ docs/source/api/react/hooks.mdx | 11 ++++ docs/source/api/react/preloading.mdx | 11 ++++ docs/source/config.json | 1 + src/react/hooks/useLoadableQuery.ts | 54 ++++++++++++++++- src/react/hooks/useQueryRefHandlers.ts | 2 +- src/react/internal/cache/QueryReference.ts | 39 +++++++++++++ .../query-preloader/createQueryPreloader.ts | 7 ++- 13 files changed, 206 insertions(+), 31 deletions(-) create mode 100644 docs/shared/Overrides/UseLoadableQueryResult.js create mode 100644 docs/source/api/react/preloading.mdx diff --git a/.api-reports/api-report-react.md b/.api-reports/api-report-react.md index e7a4e16d51c..3489e1e54c3 100644 --- a/.api-reports/api-report-react.md +++ b/.api-reports/api-report-react.md @@ -547,7 +547,7 @@ type ConcastSourcesIterable = Iterable>; export interface Context extends Record { } -// @public +// @alpha export function createQueryPreloader(client: ApolloClient): PreloadQueryFunction; // @public (undocumented) @@ -1759,13 +1759,13 @@ interface QueryOptions { // // @public export interface QueryReference { - // (undocumented) + // @internal (undocumented) [PROMISE_SYMBOL]: QueryRefPromise; // Warning: (ae-forgotten-export) The symbol "InternalQueryReference" needs to be exported by the entry point index.d.ts // - // (undocumented) + // @internal (undocumented) readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - // (undocumented) + // @alpha toPromise(): Promise>; } @@ -2251,13 +2251,13 @@ export function useLoadableQuery, TVariables>; -// @public (undocumented) +// @public export function useLoadableQuery(query: DocumentNode | TypedDocumentNode, options?: LoadableQueryHookOptions): UseLoadableQueryResult; // @public (undocumented) export type UseLoadableQueryResult = [ -LoadQueryFunction, -QueryReference | null, +loadQuery: LoadQueryFunction, +queryRef: QueryReference | null, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -2398,7 +2398,7 @@ interface WatchQueryOptions { // // @public interface QueryReference { - // (undocumented) + // @internal (undocumented) [PROMISE_SYMBOL]: QueryRefPromise; // Warning: (ae-forgotten-export) The symbol "InternalQueryReference" needs to be exported by the entry point index.d.ts // - // (undocumented) + // @internal (undocumented) readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - // (undocumented) + // @alpha toPromise(): Promise>; } @@ -2091,13 +2091,13 @@ export function useLoadableQuery, TVariables>; -// @public (undocumented) +// @public export function useLoadableQuery(query: DocumentNode | TypedDocumentNode, options?: LoadableQueryHookOptions): UseLoadableQueryResult; // @public (undocumented) export type UseLoadableQueryResult = [ -LoadQueryFunction, -QueryReference | null, +loadQuery: LoadQueryFunction, +queryRef: QueryReference | null, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -2234,7 +2234,7 @@ interface WatchQueryOptions { // // @public export interface QueryReference { - // (undocumented) + // @internal (undocumented) [PROMISE_SYMBOL]: QueryRefPromise; - // (undocumented) + // @internal (undocumented) readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - // (undocumented) + // @alpha toPromise(): Promise>; } diff --git a/.api-reports/api-report.md b/.api-reports/api-report.md index 39d55033f88..9040bd40123 100644 --- a/.api-reports/api-report.md +++ b/.api-reports/api-report.md @@ -544,7 +544,7 @@ export const concat: typeof ApolloLink.concat; // @public (undocumented) export const createHttpLink: (linkOptions?: HttpOptions) => ApolloLink; -// @public +// @alpha export function createQueryPreloader(client: ApolloClient): PreloadQueryFunction; // @public @deprecated (undocumented) @@ -2323,13 +2323,13 @@ export { QueryOptions } // // @public export interface QueryReference { - // (undocumented) + // @internal (undocumented) [PROMISE_SYMBOL]: QueryRefPromise; // Warning: (ae-forgotten-export) The symbol "InternalQueryReference" needs to be exported by the entry point index.d.ts // - // (undocumented) + // @internal (undocumented) readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - // (undocumented) + // @alpha toPromise(): Promise>; } @@ -2904,13 +2904,13 @@ export function useLoadableQuery, TVariables>; -// @public (undocumented) +// @public export function useLoadableQuery(query: DocumentNode | TypedDocumentNode, options?: LoadableQueryHookOptions): UseLoadableQueryResult; // @public (undocumented) export type UseLoadableQueryResult = [ -LoadQueryFunction, -QueryReference | null, +loadQuery: LoadQueryFunction, +queryRef: QueryReference | null, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -3077,7 +3077,7 @@ interface WriteContext extends ReadMergeModifyContext { // src/link/http/selectHttpOptionsAndBody.ts:128:32 - (ae-forgotten-export) The symbol "HttpQueryOptions" needs to be exported by the entry point index.d.ts // src/react/hooks/useBackgroundQuery.ts:29:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts // src/react/hooks/useBackgroundQuery.ts:30:3 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts -// src/react/hooks/useLoadableQuery.ts:49:5 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts +// src/react/hooks/useLoadableQuery.ts:106:1 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/.prettierignore b/.prettierignore index d1ab5b159ad..fe391b018fc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -29,6 +29,8 @@ /docs/shared/** !/docs/shared/ApiDoc !/docs/shared/ApiDoc/** +!/docs/shared/Overrides +!/docs/shared/Overrides/** node_modules/ .yalc/ diff --git a/docs/shared/Overrides/UseLoadableQueryResult.js b/docs/shared/Overrides/UseLoadableQueryResult.js new file mode 100644 index 00000000000..19a4d345d44 --- /dev/null +++ b/docs/shared/Overrides/UseLoadableQueryResult.js @@ -0,0 +1,58 @@ +import React from "react"; +import { useMDXComponents } from "@mdx-js/react"; +import { ManualTuple } from "../ApiDoc"; + +const HANDLERS = `{ + fetchMore: FetchMoreFunction; + refetch: RefetchFunction; + reset: ResetFunction; +}`; + +const RETURN_VALUE = `[ + loadQuery: LoadQueryFunction, + queryRef: QueryReference | null, + { + fetchMore: FetchMoreFunction; + refetch: RefetchFunction; + reset: ResetFunction; + } +]`; + +export function UseLoadableQueryResult() { + const MDX = useMDXComponents(); + + return ( +
+ + {RETURN_VALUE} + + A tuple of three values: + ", + description: + "A function used to imperatively load a query. Calling this function will create or update the `queryRef` returned by `useLoadableQuery`, which should be passed to `useReadQuery`.", + }, + { + name: "queryRef", + type: "QueryReference | null", + description: + "The `queryRef` used by `useReadQuery` to read the query result.", + canonicalReference: "@apollo/client!QueryReference:interface", + }, + { + name: "handlers", + description: + "Additional handlers used for the query, such as `refetch`.", + type: HANDLERS, + }, + ]} + /> +
+ ); +} + +UseLoadableQueryResult.propTypes = {}; diff --git a/docs/source/api/react/hooks.mdx b/docs/source/api/react/hooks.mdx index c6e3249253b..80ef1dc3710 100644 --- a/docs/source/api/react/hooks.mdx +++ b/docs/source/api/react/hooks.mdx @@ -10,6 +10,8 @@ api_doc: - "@apollo/client!useSubscription:function(1)" - "@apollo/client!useApolloClient:function(1)" - "@apollo/client!useReactiveVar:function(1)" + - "@apollo/client!useLoadableQuery:function(5)" + - "@apollo/client!useQueryRefHandlers:function(1)" --- import UseFragmentOptions from '../../../shared/useFragment-options.mdx'; @@ -19,6 +21,7 @@ import UseSuspenseQueryResult from '../../../shared/useSuspenseQuery-result.mdx' import UseBackgroundQueryResult from '../../../shared/useBackgroundQuery-result.mdx'; import UseReadQueryResult from '../../../shared/useReadQuery-result.mdx'; import { FunctionDetails, PropertySignatureTable, ManualTuple, InterfaceDetails } from '../../../shared/ApiDoc'; +import { UseLoadableQueryResult } from '../../../shared/Overrides/UseLoadableQueryResult' ## The `ApolloProvider` component @@ -405,6 +408,14 @@ function useReadQuery( +} +/> + + + ## `skipToken` diff --git a/docs/source/api/react/preloading.mdx b/docs/source/api/react/preloading.mdx new file mode 100644 index 00000000000..644fe13d122 --- /dev/null +++ b/docs/source/api/react/preloading.mdx @@ -0,0 +1,11 @@ +--- +title: Preloading +description: Apollo Client preloading API reference +minVersion: 3.9.0 +api_doc: + - "@apollo/client!createQueryPreloader:function(1)" +--- + +import { FunctionDetails } from '../../../shared/ApiDoc'; + + diff --git a/docs/source/config.json b/docs/source/config.json index 60b6f0b1b6e..98c46b99f90 100644 --- a/docs/source/config.json +++ b/docs/source/config.json @@ -80,6 +80,7 @@ }, "React": { "Hooks": "/api/react/hooks", + "Preloading": "/api/react/preloading", "Testing": "/api/react/testing", "SSR": "/api/react/ssr", "Components (deprecated)": "/api/react/components", diff --git a/src/react/hooks/useLoadableQuery.ts b/src/react/hooks/useLoadableQuery.ts index 796721a92fc..7c0c0cca4e6 100644 --- a/src/react/hooks/useLoadableQuery.ts +++ b/src/react/hooks/useLoadableQuery.ts @@ -41,11 +41,16 @@ export type UseLoadableQueryResult< TData = unknown, TVariables extends OperationVariables = OperationVariables, > = [ - LoadQueryFunction, - QueryReference | null, + loadQuery: LoadQueryFunction, + queryRef: QueryReference | null, { + /** {@inheritDoc @apollo/client!QueryResultDocumentation#fetchMore:member} */ fetchMore: FetchMoreFunction; + /** {@inheritDoc @apollo/client!QueryResultDocumentation#refetch:member} */ refetch: RefetchFunction; + /** + * A function that resets the `queryRef` back to `null`. + */ reset: ResetFunction; }, ]; @@ -98,6 +103,51 @@ export function useLoadableQuery< } ): UseLoadableQueryResult, TVariables>; +/** + * A hook for imperatively loading a query, such as responding to a user + * interaction. + * + * > Refer to the [Suspense - Fetching in response to user interaction](https://www.apollographql.com/docs/react/data/suspense#fetching-in-response-to-user-interaction) section for a more in-depth overview of `useLoadableQuery`. + * + * @example + * ```jsx + * import { gql, useLoadableQuery } from "@apollo/client"; + * + * const GET_GREETING = gql` + * query GetGreeting($language: String!) { + * greeting(language: $language) { + * message + * } + * } + * `; + * + * function App() { + * const [loadGreeting, queryRef] = useLoadableQuery(GET_GREETING); + * + * return ( + * <> + * + * Loading...}> + * {queryRef && } + * + * + * ); + * } + * + * function Hello({ queryRef }) { + * const { data } = useReadQuery(queryRef); + * + * return
{data.greeting.message}
; + * } + * ``` + * + * @since 3.9.0 + * @param query - A GraphQL query document parsed into an AST by `gql`. + * @param options - Options to control how the query is executed. + * @returns A tuple in the form of `[loadQuery, queryRef, handlers]` + */ export function useLoadableQuery< TData = unknown, TVariables extends OperationVariables = OperationVariables, diff --git a/src/react/hooks/useQueryRefHandlers.ts b/src/react/hooks/useQueryRefHandlers.ts index c5470e1540f..b0422afa678 100644 --- a/src/react/hooks/useQueryRefHandlers.ts +++ b/src/react/hooks/useQueryRefHandlers.ts @@ -36,7 +36,7 @@ export interface UseQueryRefHandlersResult< * // ... * } * ``` - * + * @since 3.9.0 * @param queryRef - A `QueryReference` returned from `useBackgroundQuery`, `useLoadableQuery`, or `createQueryPreloader`. */ export function useQueryRefHandlers< diff --git a/src/react/internal/cache/QueryReference.ts b/src/react/internal/cache/QueryReference.ts index 7328a0533c3..dc26adf541c 100644 --- a/src/react/internal/cache/QueryReference.ts +++ b/src/react/internal/cache/QueryReference.ts @@ -35,8 +35,47 @@ const PROMISE_SYMBOL: unique symbol = Symbol(); * suspend until the promise resolves. */ export interface QueryReference { + /** @internal */ readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; + /** @internal */ [PROMISE_SYMBOL]: QueryRefPromise; + /** + * A function that returns a promise that resolves when the query has finished + * loading. The promise resolves with the `QueryReference` itself. + * + * @remarks + * This method is useful for preloading queries in data loading routers, such + * as [React Router](https://reactrouter.com/en/main) or [TanStack Router](https://tanstack.com/router), + * to prevent routes from transitioning until the query has finished loading. + * `data` is not exposed on the promise to discourage using the data in + * `loader` functions and exposing it to your route components. Instead, we + * prefer you rely on `useReadQuery` to access the data to ensure your + * component can rerender with cache updates. If you need to access raw query + * data, use `client.query()` directly. + * + * @example + * Here's an example using React Router's `loader` function: + * ```ts + * import { createQueryPreloader } from "@apollo/client"; + * + * const preloadQuery = createQueryPreloader(client); + * + * export async function loader() { + * const queryRef = preloadQuery(GET_DOGS_QUERY); + * + * return queryRef.toPromise(); + * } + * + * export function RouteComponent() { + * const queryRef = useLoaderData(); + * const { data } = useReadQuery(queryRef); + * + * // ... + * } + * ``` + * + * @alpha + */ toPromise(): Promise>; } diff --git a/src/react/query-preloader/createQueryPreloader.ts b/src/react/query-preloader/createQueryPreloader.ts index 12b7efd7983..b7a9d22afcb 100644 --- a/src/react/query-preloader/createQueryPreloader.ts +++ b/src/react/query-preloader/createQueryPreloader.ts @@ -153,7 +153,9 @@ export interface PreloadQueryFunction { * when you want to start loading a query as early as possible outside of a * React component. * - * @param client - The ApolloClient instance that will be used to load queries + * > Refer to the [Suspense - Initiating queries outside React](https://www.apollographql.com/docs/react/data/suspense#initiating-queries-outside-react) section for a more in-depth overview. + * + * @param client - The `ApolloClient` instance that will be used to load queries * from the returned `preloadQuery` function. * @returns The `preloadQuery` function. * @@ -161,7 +163,8 @@ export interface PreloadQueryFunction { * ```js * const preloadQuery = createQueryPreloader(client); * ``` - * @experimental + * @since 3.9.0 + * @alpha */ export function createQueryPreloader( client: ApolloClient