UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

118 lines 4.75 kB
import * as React from "react"; import { NetworkStatus } from "@apollo/client"; import { getSuspenseCache } from "@apollo/client/react/internal"; import { __DEV__ } from "@apollo/client/utilities/environment"; import { variablesUnknownSymbol } from "@apollo/client/utilities/internal"; import { skipToken } from "./constants.js"; import { __use, useDeepMemo, useSuspenseHookCacheKey, wrapHook, } from "./internal/index.js"; import { validateSuspenseHookOptions } from "./internal/validateSuspenseHookOptions.js"; import { useApolloClient } from "./useApolloClient.js"; export function useSuspenseQuery(query, options) { "use no memo"; return wrapHook("useSuspenseQuery", // eslint-disable-next-line react-compiler/react-compiler useSuspenseQuery_, useApolloClient(typeof options === "object" ? options.client : undefined))(query, options ?? {}); } function useSuspenseQuery_(query, options) { const client = useApolloClient(options.client); const suspenseCache = getSuspenseCache(client); const watchQueryOptions = useWatchQueryOptions({ client, query, options, }); const { fetchPolicy } = watchQueryOptions; const cacheKey = useSuspenseHookCacheKey(query, options); const queryRef = suspenseCache.getQueryRef(cacheKey, () => client.watchQuery(watchQueryOptions)); let [current, setPromise] = React.useState([queryRef.key, queryRef.promise]); // This saves us a re-execution of the render function when a variable changed. if (current[0] !== queryRef.key) { // eslint-disable-next-line react-compiler/react-compiler current[0] = queryRef.key; current[1] = queryRef.promise; } let promise = current[1]; if (queryRef.didChangeOptions(watchQueryOptions)) { current[1] = promise = queryRef.applyOptions(watchQueryOptions); } React.useEffect(() => { const dispose = queryRef.retain(); const removeListener = queryRef.listen((promise) => { setPromise([queryRef.key, promise]); }); return () => { removeListener(); dispose(); }; }, [queryRef]); const skipResult = React.useMemo(() => { const error = queryRef.result.error; const complete = !!queryRef.result.data; return { loading: false, data: queryRef.result.data, dataState: queryRef.result.dataState, networkStatus: error ? NetworkStatus.error : NetworkStatus.ready, error, complete, partial: !complete, }; }, [queryRef.result]); const result = fetchPolicy === "standby" ? skipResult : __use(promise); const fetchMore = React.useCallback((options) => { const promise = queryRef.fetchMore(options); setPromise([queryRef.key, queryRef.promise]); return promise; }, [queryRef]); const refetch = React.useCallback((variables) => { const promise = queryRef.refetch(variables); setPromise([queryRef.key, queryRef.promise]); return promise; }, [queryRef]); // TODO: The internalQueryRef doesn't have TVariables' type information so we have to cast it here const subscribeToMore = queryRef.observable .subscribeToMore; return React.useMemo(() => { return { client, data: result.data, dataState: result.dataState, error: result.error, networkStatus: result.networkStatus, fetchMore, refetch, subscribeToMore, }; }, [client, fetchMore, refetch, result, subscribeToMore]); } export function useWatchQueryOptions({ client, query, options, }) { return useDeepMemo(() => { if (options === skipToken) { return { query, fetchPolicy: "standby", [variablesUnknownSymbol]: true, }; } const fetchPolicy = options.fetchPolicy || client.defaultOptions.watchQuery?.fetchPolicy || "cache-first"; const watchQueryOptions = { ...options, fetchPolicy, query, notifyOnNetworkStatusChange: false, nextFetchPolicy: void 0, }; if (__DEV__) { validateSuspenseHookOptions(watchQueryOptions); } // Assign the updated fetch policy after our validation since `standby` is // not a supported fetch policy on its own without the use of `skip`. if (options.skip) { watchQueryOptions.fetchPolicy = "standby"; } return watchQueryOptions; }, [client, options, query]); } //# sourceMappingURL=useSuspenseQuery.js.map