From bda26822e954e7cf0a61761d52173ec99f500f42 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Wed, 5 Feb 2025 13:51:23 +0100 Subject: [PATCH] `useReadQuery`/`useQueryRefHandlers`: Fix a "hook order" warning that might be emitted in React 19 dev mode. --- .changeset/large-timers-lay.md | 5 +++++ src/react/hooks/useQueryRefHandlers.ts | 21 +++++++++---------- src/react/hooks/useReadQuery.ts | 29 ++++++++++++-------------- 3 files changed, 28 insertions(+), 27 deletions(-) create mode 100644 .changeset/large-timers-lay.md diff --git a/.changeset/large-timers-lay.md b/.changeset/large-timers-lay.md new file mode 100644 index 00000000000..8712178dbf1 --- /dev/null +++ b/.changeset/large-timers-lay.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +`useReadQuery`/`useQueryRefHandlers`: Fix a "hook order" warning that might be emitted in React 19 dev mode. diff --git a/src/react/hooks/useQueryRefHandlers.ts b/src/react/hooks/useQueryRefHandlers.ts index 8204e3e5df7..176ed1413b0 100644 --- a/src/react/hooks/useQueryRefHandlers.ts +++ b/src/react/hooks/useQueryRefHandlers.ts @@ -16,6 +16,8 @@ import type { import type { FetchMoreQueryOptions } from "../../core/watchQueryOptions.js"; import { useApolloClient } from "./useApolloClient.js"; import { wrapHook } from "./internal/index.js"; +import { ApolloClient } from "../../core/ApolloClient.js"; +import type { ObservableQuery } from "../../core/ObservableQuery.js"; export interface UseQueryRefHandlersResult< TData = unknown, @@ -55,21 +57,18 @@ export function useQueryRefHandlers< queryRef: QueryRef ): UseQueryRefHandlersResult { const unwrapped = unwrapQueryRef(queryRef); + const clientOrObsQuery = useApolloClient( + unwrapped ? + // passing an `ObservableQuery` is not supported by the types, but it will + // return any truthy value that is passed in as an override so we cast the result + (unwrapped["observable"] as any) + : undefined + ) as ApolloClient | ObservableQuery; return wrapHook( "useQueryRefHandlers", useQueryRefHandlers_, - unwrapped ? - unwrapped["observable"] - // in the case of a "transported" queryRef object, we need to use the - // client that's available to us at the current position in the React tree - // that ApolloClient will then have the job to recreate a real queryRef from - // the transported object - // This is just a context read - it's fine to do this conditionally. - // This hook wrapper also shouldn't be optimized by React Compiler. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/rules-of-hooks - : useApolloClient() + clientOrObsQuery )(queryRef); } diff --git a/src/react/hooks/useReadQuery.ts b/src/react/hooks/useReadQuery.ts index 5c444e0eb7c..44c4ec8cecd 100644 --- a/src/react/hooks/useReadQuery.ts +++ b/src/react/hooks/useReadQuery.ts @@ -10,7 +10,11 @@ import { __use, wrapHook } from "./internal/index.js"; import { toApolloError } from "./useSuspenseQuery.js"; import { useSyncExternalStore } from "./useSyncExternalStore.js"; import type { ApolloError } from "../../errors/index.js"; -import type { NetworkStatus } from "../../core/index.js"; +import type { + ApolloClient, + NetworkStatus, + ObservableQuery, +} from "../../core/index.js"; import { useApolloClient } from "./useApolloClient.js"; import type { MaybeMasked } from "../../masking/index.js"; @@ -43,22 +47,15 @@ export function useReadQuery( queryRef: QueryRef ): UseReadQueryResult { const unwrapped = unwrapQueryRef(queryRef); - - return wrapHook( - "useReadQuery", - useReadQuery_, + const clientOrObsQuery = useApolloClient( unwrapped ? - unwrapped["observable"] - // in the case of a "transported" queryRef object, we need to use the - // client that's available to us at the current position in the React tree - // that ApolloClient will then have the job to recreate a real queryRef from - // the transported object - // This is just a context read - it's fine to do this conditionally. - // This hook wrapper also shouldn't be optimized by React Compiler. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/rules-of-hooks - : useApolloClient() - )(queryRef); + // passing an `ObservableQuery` is not supported by the types, but it will + // return any truthy value that is passed in as an override so we cast the result + (unwrapped["observable"] as any) + : undefined + ) as ApolloClient | ObservableQuery; + + return wrapHook("useReadQuery", useReadQuery_, clientOrObsQuery)(queryRef); } function useReadQuery_(