UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

1,054 lines (790 loc) 776 kB
# @apollo/client ## 4.3.0-alpha.1 ### Patch Changes - [#13268](https://github.com/apollographql/apollo-client/pull/13268) [`419e2b5`](https://github.com/apollographql/apollo-client/commit/419e2b5bfe573d1eb4c3a0ff7aa9084e6aaa2f37) Thanks [@DaleSeo](https://github.com/DaleSeo)! - Align the remaining cache generic constraints with `Cache.Implementation`. The deprecated React mutation types (`MutationHookOptions`, `MutationFunctionOptions`, `MutationTuple`) and the internal `InternalRefetchQueriesOptions` and `QueryInfo` types still constrained their cache type parameter to `ApolloCache`, so they now match the rest of the overridable cache API. ## 4.3.0-alpha.0 ### Minor Changes - [#13250](https://github.com/apollographql/apollo-client/pull/13250) [`bad7035`](https://github.com/apollographql/apollo-client/commit/bad7035565e15c18800080d9e0abf1d89b3d82fa) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add the ability to define the cache type for the client. `client.cache` currently returns `ApolloCache` as the cache type regardless of what cache you've provided to `ApolloClient`. Declare the cache type using the `cache` property in the `TypeOverrides` interface to set the cache implementation used for the client. ```ts // apollo.d.ts import type { InMemoryCache } from "@apollo/client"; declare module "@apollo/client" { export interface TypeOverrides { cache: InMemoryCache; } } ``` Now anywhere `cache` is accessible, the type is the declared cache type: ```ts client.cache; // ^? InMemoryCache client.mutate({ update: (cache) => { // ^? InMemoryCache }, }); ``` > [!NOTE] > Setting a cache type enforces that cache type in the `cache` option for the `ApolloClient` constructor. ## 4.2.3 ### Patch Changes - [#13254](https://github.com/apollographql/apollo-client/pull/13254) [`66e9dfc`](https://github.com/apollographql/apollo-client/commit/66e9dfcf7964345dac949ab4c6004460d224d1cf) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add support for `graphql` v17 as a valid peer dependency. ## 4.2.2 ### Patch Changes - [#13184](https://github.com/apollographql/apollo-client/pull/13184) [`c207b88`](https://github.com/apollographql/apollo-client/commit/c207b886026114943dc7f5c85e997a1938e74cfe) Thanks [@audrius-savickas](https://github.com/audrius-savickas)! - Preserve referential equality of masked data on refetch when the result is deeply equal to the previous result. ## 4.2.1 ### Patch Changes - [#13248](https://github.com/apollographql/apollo-client/pull/13248) [`062ffe3`](https://github.com/apollographql/apollo-client/commit/062ffe3ecfeda8630a4ad3ced40ce58193199b74) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fixes an issue where `useLazyQuery` would not apply a changed `pollInterval` between renders. ## 4.2.0 ### Minor Changes - [#13132](https://github.com/apollographql/apollo-client/pull/13132) [`f3ce805`](https://github.com/apollographql/apollo-client/commit/f3ce805425d10a9666218a8e109288a2d46dcab1) Thanks [@phryneas](https://github.com/phryneas)! - Introduce "classic" and "modern" method and hook signatures. Apollo Client 4.2 introduces two signature styles for methods and hooks. All signatures previously present are now "classic" signatures, and a new set of "modern" signatures are added alongside them. **Classic signatures** are the default and are identical to the signatures before Apollo Client 4.2, preserving backward compatibility. Classic signatures still work with manually specified TypeScript generics (e.g., `useSuspenseQuery<MyData>(...)`). However, manually specifying generics has been discouraged for a long time—instead, we recommend using `TypedDocumentNode` to automatically infer types, which provides more accurate results without any manual annotations. **Modern signatures** automatically incorporate your declared `defaultOptions` into return types, providing more accurate types. Modern signatures infer types from the document node and do not support manually passing generic type arguments; TypeScript will produce a type error if you attempt to do so. Methods and hooks automatically switch to modern signatures the moment any non-optional property is declared in `DeclareDefaultOptions`. The switch happens across all methods and hooks globally: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy: "all"; // non-optional → modern signatures activated automatically } } } } ``` Users can also manually switch to modern signatures without declaring any `defaultOptions`, for example when wanting accurate type inference without relying on global `defaultOptions`: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { export interface TypeOverrides { signatureStyle: "modern"; } } ``` Users can do a global `DeclareDefaultOptions` type augmentation and then manually switch back to "classic" for migration purposes: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { export interface TypeOverrides { signatureStyle: "classic"; } } ``` Note that this is **not recommended for long-term use**. When combined with `DeclareDefaultOptions`, switching back to classic results in the same incorrect types as before Apollo Client 4.2—methods and hooks will not reflect the `defaultOptions` you've declared. - [#13130](https://github.com/apollographql/apollo-client/pull/13130) [`dd12231`](https://github.com/apollographql/apollo-client/commit/dd122316028b55307de4a40335512307c8fa916a) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Improve the accuracy of `client.query` return type to better detect the current `errorPolicy`. The `data` property is no longer nullable when the `errorPolicy` is `none`. This makes it possible to remove the `undefined` checks or optional chaining in most cases. - [#13210](https://github.com/apollographql/apollo-client/pull/13210) [`1f9a428`](https://github.com/apollographql/apollo-client/commit/1f9a4287eb1eeef2cc08c81c92961f1cecd0dbca) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add support for automatic event-based refetching, such as window focus. The `RefetchEventManager` class handles automatic refetches in response to events. Apollo Client provides built-in sources for window focus and network reconnect as `windowFocusSource` and `onlineSource`. Event refetching is fully opt-in. Create and pass a `RefetchEventManager` instance to the `ApolloClient` constructor to activate the event listeners. ```ts import { ApolloClient, InMemoryCache, RefetchEventManager, windowFocusSource, onlineSource, } from "@apollo/client"; const client = new ApolloClient({ link, cache: new InMemoryCache(), refetchEventManager: new RefetchEventManager({ sources: { // Refetch when window is focused windowFocus: windowFocusSource, // Refetch when the user comes back online online: onlineSource, }, }), }); ``` By default, all active queries refetch when the events fire. Queries can opt out per-event or disable all event refetches: ```ts // Skip refetch on window focus for this query, but keep `online` useQuery(QUERY, { refetchOn: { windowFocus: false }, }); // Disable all event-driven refetches for this query useQuery(OTHER_QUERY, { refetchOn: false, }); // Enable every event for this query, regardless of defaultOptions useQuery(LIVE_DASHBOARD, { refetchOn: true, }); // Dynamically enable or disable a refetch when the event fires useQuery(LIVE_DASHBOARD, { refetchOn: ({ source, payload }) => { if (source === "windowFocus") { // payload is the data associated with the event return someCondition(payload); } return true; }, }); // Dynamically enable or disable a refetch for a specific event useQuery(LIVE_DASHBOARD, { refetchOn: { windowFocus: ({ payload }) => { // payload is the data associated with the event return someCondition(payload); }, }, }); ``` To enable per-query opt-in rather than opt-out, set `defaultOptions.watchQuery.refetchOn` to `false` and enable it per-query instead. ```ts const client = new ApolloClient({ link, cache, refetchEventManager: new RefetchEventManager({ sources: { windowFocus: windowFocusSource }, }), defaultOptions: { watchQuery: { refetchOn: false }, }, }); // Only this query refetches on window focus useQuery(DASHBOARD_QUERY, { refetchOn: { windowFocus: true } }); ``` When `defaultOptions.watchQuery.refetchOn` and per-query `refetchOn` options are provided, the objects are merged together. ### Custom events You can also add your own custom events that trigger refetches. Register your event name and payload type using TypeScript module augmentation, then provide a source function that returns an Observable. The source's emitted value becomes the event's `payload`. ```ts import { Observable } from "@apollo/client"; import { filter } from "rxjs"; import { AppState, AppStateStatus, Platform } from "react-native"; declare module "@apollo/client" { interface RefetchEvents { reactNativeAppStatus: AppStateStatus; } } const refetchEventManager = new RefetchEventManager({ sources: { reactNativeAppStatus: () => { return new Observable((observer) => { const subscription = AppState.addEventListener("change", (status) => { observer.next(status); }); return () => subscription.remove(); }).pipe( filter((status) => Platform.OS !== "web" && status === "active") ); }, }, }); // Disable per-query by setting the event to false useQuery(QUERY, { refetchOn: { reactNativeAppStatus: false } }); ``` ### Manually trigger an event refetch Refetches can be triggered imperatively by calling `emit` with the event name and its payload (if any). ```ts refetchEventManager.emit("reactNativeAppStatus", "active"); ``` #### Sourceless events A source that has no automatic detection logic but still wants imperative `emit` support can be declared as `true`. Type the event as `void` to omit the payload argument. ```ts declare module "@apollo/client" { interface RefetchEvents { userTriggered: void; } } const refetchEventManager = new RefetchEventManager({ sources: { userTriggered: true }, }); refetchEventManager.emit("userTriggered"); ``` Note: Calling `emit` on an event without a registered source will log a warning and result in a no-op. ### Custom handlers When an event fires, the default handler calls `client.refetchQueries({ include: "active" })` filtered by each query's `refetchOn` setting. You can override the handler for an event to add your own custom filtering. For example, to refetch all queries, including `standby` queries, define a handler for the event: ```ts const refetchEventManager = new RefetchEventManager({ // ... handlers: { userTriggered: ({ client, source, payload, matchesRefetchOn }) => { return client.refetchQueries({ include: "all", onQueryUpdated: (observableQuery) => { return matchesRefetchOn(observableQuery); }, }); }, }, }); ``` Handlers must return either a `RefetchQueriesResult` or `void`. Returning `void` skips refetching for the event. - [#13232](https://github.com/apollographql/apollo-client/pull/13232) [`f1b541f`](https://github.com/apollographql/apollo-client/commit/f1b541fed4111028b6842727178288156582e669) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Version bump to `rc`. - [#13206](https://github.com/apollographql/apollo-client/pull/13206) [`08fccab`](https://github.com/apollographql/apollo-client/commit/08fccab68822e99c6edd539cb4162d1a3df4f4c9) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Extend the `defaultOptions` type-safety work to `client.mutate` and `useMutation`. The `errorPolicy` option now flows through to the result types for mutations in the same way it already does for queries: - `ApolloClient.MutateResult<TData, TErrorPolicy>` maps `errorPolicy` to the concrete shape of `data` and `error`: - `"none"` → `{ data: TData; error?: never }` - `"all"` → `{ data: TData | undefined; error?: ErrorLike }` - `"ignore"` → `{ data: TData | undefined; error?: never }` - `client.mutate` and `useMutation` pick up the declared `defaultOptions.mutate.errorPolicy` and the explicit `errorPolicy` on each call to narrow return types accordingly. - `useMutation.Result.error` is narrowed to `undefined` when `errorPolicy` is `"ignore"`, since `client.mutate` never resolves with an error in that case. `DeclareDefaultOptions.Mutate` already accepted `errorPolicy`; the new behavior is that once you declare it, hook and method return types reflect it: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface Mutate { errorPolicy: "all"; } } } } ``` ```ts const result = await client.mutate({ mutation: MUTATION }); result.data; // ^? TData | undefined result.error; // ^? ErrorLike | undefined ``` Setting `errorPolicy` on an individual call overrides the default for that call's return type. - [#13222](https://github.com/apollographql/apollo-client/pull/13222) [`b93c172`](https://github.com/apollographql/apollo-client/commit/b93c1723b4b7a9d1296ddd57035bc4fe39c8d971) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Extend the `defaultOptions` type-safety work to `preloadQuery` (returned from `createQueryPreloader`). Defaults declared in `DeclareDefaultOptions.WatchQuery` now work with `preloadQuery` to ensure the `PreloadedQueryRef`'s data states are correctly set. ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy: "all"; } } } } ``` ```ts const preloadQuery = createQueryPreloader(client); const queryRef = preloadQuery(QUERY); // ^? PreloadedQueryRef<TData, TVariables, "complete" | "streaming" | "empty"> ``` - [#13132](https://github.com/apollographql/apollo-client/pull/13132) [`f3ce805`](https://github.com/apollographql/apollo-client/commit/f3ce805425d10a9666218a8e109288a2d46dcab1) Thanks [@phryneas](https://github.com/phryneas)! - Synchronize method and hook return types with `defaultOptions`. Prior to this change, the following code snippet would always apply: ```ts declare const MY_QUERY: TypedDocumentNode<TData, TVariables>; const result1 = useSuspenseQuery(MY_QUERY); result1.data; // ^? TData const result2 = useSuspenseQuery(MY_QUERY, { errorPolicy: "all" }); result2.data; // ^? TData | undefined ``` While these types are generally correct, if you were to set `errorPolicy: 'all'` as a default option, the type of `result.data` for the first query would remain `TData` instead of changing to `TData | undefined` to match the runtime behavior. We are now enforcing that certain `defaultOptions` types need to be registered globally. This means that if you want to use `errorPolicy: 'all'` as a default option for a query, you will need to register its type like this: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { // possible global-registered values: // * `errorPolicy` // * `returnPartialData` errorPolicy: "all"; } interface Query { // possible global-registered values: // * `errorPolicy` } interface Mutate { // possible global-registered values: // * `errorPolicy` } } } } ``` Once this type declaration is in place, the type of `result.data` in the above example will correctly be changed to `TData | undefined`, reflecting the possibility that if an error occurs, `data` might be `undefined`. Manually specifying `useSuspenseQuery(MY_QUERY, { errorPolicy: "none" });` changes `result.data` to `TData` to reflect the local override. This change means that you will need to declare your default options types in order to use `defaultOptions` with `ApolloClient`, otherwise you will see a TypeScript error. Without the type declaration, the following (previously valid) code will now error: ```ts new ApolloClient({ link: ApolloLink.empty(), cache: new InMemoryCache(), defaultOptions: { watchQuery: { // results in a type error: // Type '"all"' is not assignable to type '"A default option for watchQuery.errorPolicy must be declared in ApolloClient.DeclareDefaultOptions before usage. See https://www.apollographql.com/docs/react/data/typescript#declaring-default-options-for-type-safety."'. errorPolicy: "all", }, }, }); ``` If you are creating multiple instances of Apollo Client with conflicting default options and you cannot register a single `defaultOptions` value as a result, you can relax the constraints by declaring those options as union types covering all values used by all clients. The properties can be required (to enforce them in `defaultOptions`) or optional (if some constructor calls won't pass a value): ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { export namespace ApolloClient { export namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy?: "none" | "all" | "ignore"; returnPartialData?: boolean; } interface Query { errorPolicy?: "none" | "all" | "ignore"; } interface Mutate { errorPolicy?: "none" | "all" | "ignore"; } } } } ``` With this declaration, the `ApolloClient` constructor accepts any of those values in `defaultOptions`. The tradeoff is that hook and method return types become more generic. For example, calling `useSuspenseQuery` without an explicit `errorPolicy` will return a result typed as if all error policies are possible, since TypeScript can't know which specific value your instance uses at runtime. Note that making a property optional (`errorPolicy?:`) is equivalent to adding the TypeScript default value (`"none"`) to the union. So `errorPolicy?: "all" | "ignore"` has the same effect on return types as `errorPolicy: "none" | "all" | "ignore"`, because TypeScript assumes the option could also be absent (i.e., `"none"`). You can also use a **partial union** that only lists the values you actually use. For example, if you only ever use `"all"` or `"ignore"`, declare `errorPolicy: "all" | "ignore"` (required) to keep the union narrow and avoid unused values broadening your signatures unnecessarily. ### Patch Changes - [#13217](https://github.com/apollographql/apollo-client/pull/13217) [`790f987`](https://github.com/apollographql/apollo-client/commit/790f987ed65435159dd2c6df5fe2fa01587a179e) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix the deprecation for the classic signatures for function overloads that rely on type inference from a `TypedDocumentNode`. The deprecation now only applies to classic signatures that provide explicit type arguments to encourage the use of `TypedDocumentNode`. - [#13166](https://github.com/apollographql/apollo-client/pull/13166) [`0537d97`](https://github.com/apollographql/apollo-client/commit/0537d97161a51479141a182d869458912e1b8e1d) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Release changes in 4.1.5 and 4.1.6. - [#13215](https://github.com/apollographql/apollo-client/pull/13215) [`54c9eb7`](https://github.com/apollographql/apollo-client/commit/54c9eb7f95d3cd12dc5d12ec27090f1f23b0c471) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Ensure the options object for the `useQuery`, `useSuspenseQuery`, and `useBackgroundQuery` hooks provide proper IntelliSense suggestions. - [#13229](https://github.com/apollographql/apollo-client/pull/13229) [`9a7f65a`](https://github.com/apollographql/apollo-client/commit/9a7f65a0059433c83307ef2d8117dac67947d791) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix `refetchOn` merging when `defaultOptions.watchQuery.refetchOn` is set to a non-object value (`false`, `true`, or a function) and the per-query `refetchOn` is an object. Previously the per-query object completely replaced the default so unspecified events fell back to "enabled" regardless of the default. The `defaultOptions` value now applies to any event the per-query object does not explicitly configure: - `false` - unspecified events stay disabled - `true` - unspecified events refetch - Callback function - the function is called for unspecified events to determine whether to refetch ```ts const client = new ApolloClient({ // ... defaultOptions: { watchQuery: { refetchOn: false, }, }, }); // Only `windowFocus` refetches. Other events stay disabled per the default. useQuery(QUERY, { refetchOn: { windowFocus: true } }); ``` - [#13230](https://github.com/apollographql/apollo-client/pull/13230) [`b25b659`](https://github.com/apollographql/apollo-client/commit/b25b6593f5d968db505b127e7ff7f2bb2419d5ee) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add the ability to override the default event handler on `RefetchEventManager`. The default handler runs when no per-source handler is configured for an event. Provide a custom handler via the `defaultHandler` constructor option or the `setDefaultEventHandler` instance method. ```ts new RefetchEventManager({ defaultHandler: ({ client, matchesRefetchOn }) => { return client.refetchQueries({ include: "all", onQueryUpdated: matchesRefetchOn, }); }, }); ``` ## 4.2.0-rc.0 ### Minor Changes - [#13232](https://github.com/apollographql/apollo-client/pull/13232) [`f1b541f`](https://github.com/apollographql/apollo-client/commit/f1b541fed4111028b6842727178288156582e669) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Version bump to `rc`. ## 4.2.0-alpha.8 ### Patch Changes - [#13229](https://github.com/apollographql/apollo-client/pull/13229) [`9a7f65a`](https://github.com/apollographql/apollo-client/commit/9a7f65a0059433c83307ef2d8117dac67947d791) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix `refetchOn` merging when `defaultOptions.watchQuery.refetchOn` is set to a non-object value (`false`, `true`, or a function) and the per-query `refetchOn` is an object. Previously the per-query object completely replaced the default so unspecified events fell back to "enabled" regardless of the default. The `defaultOptions` value now applies to any event the per-query object does not explicitly configure: - `false` - unspecified events stay disabled - `true` - unspecified events refetch - Callback function - the function is called for unspecified events to determine whether to refetch ```ts const client = new ApolloClient({ // ... defaultOptions: { watchQuery: { refetchOn: false, }, }, }); // Only `windowFocus` refetches. Other events stay disabled per the default. useQuery(QUERY, { refetchOn: { windowFocus: true } }); ``` - [#13230](https://github.com/apollographql/apollo-client/pull/13230) [`b25b659`](https://github.com/apollographql/apollo-client/commit/b25b6593f5d968db505b127e7ff7f2bb2419d5ee) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add the ability to override the default event handler on `RefetchEventManager`. The default handler runs when no per-source handler is configured for an event. Provide a custom handler via the `defaultHandler` constructor option or the `setDefaultEventHandler` instance method. ```ts new RefetchEventManager({ defaultHandler: ({ client, matchesRefetchOn }) => { return client.refetchQueries({ include: "all", onQueryUpdated: matchesRefetchOn, }); }, }); ``` ## 4.2.0-alpha.7 ### Minor Changes - [#13222](https://github.com/apollographql/apollo-client/pull/13222) [`b93c172`](https://github.com/apollographql/apollo-client/commit/b93c1723b4b7a9d1296ddd57035bc4fe39c8d971) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Extend the `defaultOptions` type-safety work to `preloadQuery` (returned from `createQueryPreloader`). Defaults declared in `DeclareDefaultOptions.WatchQuery` now work with `preloadQuery` to ensure the `PreloadedQueryRef`'s data states are correctly set. ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy: "all"; } } } } ``` ```ts const preloadQuery = createQueryPreloader(client); const queryRef = preloadQuery(QUERY); // ^? PreloadedQueryRef<TData, TVariables, "complete" | "streaming" | "empty"> ``` ## 4.2.0-alpha.6 ### Patch Changes - [#13217](https://github.com/apollographql/apollo-client/pull/13217) [`790f987`](https://github.com/apollographql/apollo-client/commit/790f987ed65435159dd2c6df5fe2fa01587a179e) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix the deprecation for the classic signatures for function overloads that rely on type inference from a `TypedDocumentNode`. The deprecation now only applies to classic signatures that provide explicit type arguments to encourage the use of `TypedDocumentNode`. ## 4.2.0-alpha.5 ### Patch Changes - [#13215](https://github.com/apollographql/apollo-client/pull/13215) [`54c9eb7`](https://github.com/apollographql/apollo-client/commit/54c9eb7f95d3cd12dc5d12ec27090f1f23b0c471) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Ensure the options object for the `useQuery`, `useSuspenseQuery`, and `useBackgroundQuery` hooks provide proper IntelliSense suggestions. ## 4.2.0-alpha.4 ### Minor Changes - [#13210](https://github.com/apollographql/apollo-client/pull/13210) [`1f9a428`](https://github.com/apollographql/apollo-client/commit/1f9a4287eb1eeef2cc08c81c92961f1cecd0dbca) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add support for automatic event-based refetching, such as window focus. The `RefetchEventManager` class handles automatic refetches in response to events. Apollo Client provides built-in sources for window focus and network reconnect as `windowFocusSource` and `onlineSource`. Event refetching is fully opt-in. Create and pass a `RefetchEventManager` instance to the `ApolloClient` constructor to activate the event listeners. ```ts import { ApolloClient, InMemoryCache, RefetchEventManager, windowFocusSource, onlineSource, } from "@apollo/client"; const client = new ApolloClient({ link, cache: new InMemoryCache(), refetchEventManager: new RefetchEventManager({ sources: { // Refetch when window is focused windowFocus: windowFocusSource, // Refetch when the user comes back online online: onlineSource, }, }), }); ``` By default, all active queries refetch when the events fire. Queries can opt out per-event or disable all event refetches: ```ts // Skip refetch on window focus for this query, but keep `online` useQuery(QUERY, { refetchOn: { windowFocus: false }, }); // Disable all event-driven refetches for this query useQuery(OTHER_QUERY, { refetchOn: false, }); // Enable every event for this query, regardless of defaultOptions useQuery(LIVE_DASHBOARD, { refetchOn: true, }); // Dynamically enable or disable a refetch when the event fires useQuery(LIVE_DASHBOARD, { refetchOn: ({ source, payload }) => { if (source === "windowFocus") { // payload is the data associated with the event return someCondition(payload); } return true; }, }); // Dynamically enable or disable a refetch for a specific event useQuery(LIVE_DASHBOARD, { refetchOn: { windowFocus: ({ payload }) => { // payload is the data associated with the event return someCondition(payload); }, }, }); ``` To enable per-query opt-in rather than opt-out, set `defaultOptions.watchQuery.refetchOn` to `false` and enable it per-query instead. ```ts const client = new ApolloClient({ link, cache, refetchEventManager: new RefetchEventManager({ sources: { windowFocus: windowFocusSource }, }), defaultOptions: { watchQuery: { refetchOn: false }, }, }); // Only this query refetches on window focus useQuery(DASHBOARD_QUERY, { refetchOn: { windowFocus: true } }); ``` When `defaultOptions.watchQuery.refetchOn` and per-query `refetchOn` options are provided, the objects are merged together. ### Custom events You can also add your own custom events that trigger refetches. Register your event name and payload type using TypeScript module augmentation, then provide a source function that returns an Observable. The source's emitted value becomes the event's `payload`. ```ts import { Observable } from "@apollo/client"; import { filter } from "rxjs"; import { AppState, AppStateStatus, Platform } from "react-native"; declare module "@apollo/client" { interface RefetchEvents { reactNativeAppStatus: AppStateStatus; } } const refetchEventManager = new RefetchEventManager({ sources: { reactNativeAppStatus: () => { return new Observable((observer) => { const subscription = AppState.addEventListener("change", (status) => { observer.next(status); }); return () => subscription.remove(); }).pipe( filter((status) => Platform.OS !== "web" && status === "active") ); }, }, }); // Disable per-query by setting the event to false useQuery(QUERY, { refetchOn: { reactNativeAppStatus: false } }); ``` ### Manually trigger an event refetch Refetches can be triggered imperatively by calling `emit` with the event name and its payload (if any). ```ts refetchEventManager.emit("reactNativeAppStatus", "active"); ``` #### Sourceless events A source that has no automatic detection logic but still wants imperative `emit` support can be declared as `true`. Type the event as `void` to omit the payload argument. ```ts declare module "@apollo/client" { interface RefetchEvents { userTriggered: void; } } const refetchEventManager = new RefetchEventManager({ sources: { userTriggered: true }, }); refetchEventManager.emit("userTriggered"); ``` Note: Calling `emit` on an event without a registered source will log a warning and result in a no-op. ### Custom handlers When an event fires, the default handler calls `client.refetchQueries({ include: "active" })` filtered by each query's `refetchOn` setting. You can override the handler for an event to add your own custom filtering. For example, to refetch all queries, including `standby` queries, define a handler for the event: ```ts const refetchEventManager = new RefetchEventManager({ // ... handlers: { userTriggered: ({ client, source, payload, matchesRefetchOn }) => { return client.refetchQueries({ include: "all", onQueryUpdated: (observableQuery) => { return matchesRefetchOn(observableQuery); }, }); }, }, }); ``` Handlers must return either a `RefetchQueriesResult` or `void`. Returning `void` skips refetching for the event. ## 4.2.0-alpha.3 ### Minor Changes - [#13206](https://github.com/apollographql/apollo-client/pull/13206) [`08fccab`](https://github.com/apollographql/apollo-client/commit/08fccab68822e99c6edd539cb4162d1a3df4f4c9) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Extend the `defaultOptions` type-safety work to `client.mutate` and `useMutation`. The `errorPolicy` option now flows through to the result types for mutations in the same way it already does for queries: - `ApolloClient.MutateResult<TData, TErrorPolicy>` maps `errorPolicy` to the concrete shape of `data` and `error`: - `"none"` → `{ data: TData; error?: never }` - `"all"` → `{ data: TData | undefined; error?: ErrorLike }` - `"ignore"` → `{ data: TData | undefined; error?: never }` - `client.mutate` and `useMutation` pick up the declared `defaultOptions.mutate.errorPolicy` and the explicit `errorPolicy` on each call to narrow return types accordingly. - `useMutation.Result.error` is narrowed to `undefined` when `errorPolicy` is `"ignore"`, since `client.mutate` never resolves with an error in that case. `DeclareDefaultOptions.Mutate` already accepted `errorPolicy`; the new behavior is that once you declare it, hook and method return types reflect it: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface Mutate { errorPolicy: "all"; } } } } ``` ```ts const result = await client.mutate({ mutation: MUTATION }); result.data; // ^? TData | undefined result.error; // ^? ErrorLike | undefined ``` Setting `errorPolicy` on an individual call overrides the default for that call's return type. ## 4.2.0-alpha.2 ### Minor Changes - [#13132](https://github.com/apollographql/apollo-client/pull/13132) [`f3ce805`](https://github.com/apollographql/apollo-client/commit/f3ce805425d10a9666218a8e109288a2d46dcab1) Thanks [@phryneas](https://github.com/phryneas)! - Introduce "classic" and "modern" method and hook signatures. Apollo Client 4.2 introduces two signature styles for methods and hooks. All signatures previously present are now "classic" signatures, and a new set of "modern" signatures are added alongside them. **Classic signatures** are the default and are identical to the signatures before Apollo Client 4.2, preserving backward compatibility. Classic signatures still work with manually specified TypeScript generics (e.g., `useSuspenseQuery<MyData>(...)`). However, manually specifying generics has been discouraged for a long time—instead, we recommend using `TypedDocumentNode` to automatically infer types, which provides more accurate results without any manual annotations. **Modern signatures** automatically incorporate your declared `defaultOptions` into return types, providing more accurate types. Modern signatures infer types from the document node and do not support manually passing generic type arguments; TypeScript will produce a type error if you attempt to do so. Methods and hooks automatically switch to modern signatures the moment any non-optional property is declared in `DeclareDefaultOptions`. The switch happens across all methods and hooks globally: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy: "all"; // non-optional → modern signatures activated automatically } } } } ``` Users can also manually switch to modern signatures without declaring any `defaultOptions`, for example when wanting accurate type inference without relying on global `defaultOptions`: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { export interface TypeOverrides { signatureStyle: "modern"; } } ``` Users can do a global `DeclareDefaultOptions` type augmentation and then manually switch back to "classic" for migration purposes: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { export interface TypeOverrides { signatureStyle: "classic"; } } ``` Note that this is **not recommended for long-term use**. When combined with `DeclareDefaultOptions`, switching back to classic results in the same incorrect types as before Apollo Client 4.2—methods and hooks will not reflect the `defaultOptions` you've declared. - [#13132](https://github.com/apollographql/apollo-client/pull/13132) [`f3ce805`](https://github.com/apollographql/apollo-client/commit/f3ce805425d10a9666218a8e109288a2d46dcab1) Thanks [@phryneas](https://github.com/phryneas)! - Synchronize method and hook return types with `defaultOptions`. Prior to this change, the following code snippet would always apply: ```ts declare const MY_QUERY: TypedDocumentNode<TData, TVariables>; const result1 = useSuspenseQuery(MY_QUERY); result1.data; // ^? TData const result2 = useSuspenseQuery(MY_QUERY, { errorPolicy: "all" }); result2.data; // ^? TData | undefined ``` While these types are generally correct, if you were to set `errorPolicy: 'all'` as a default option, the type of `result.data` for the first query would remain `TData` instead of changing to `TData | undefined` to match the runtime behavior. We are now enforcing that certain `defaultOptions` types need to be registered globally. This means that if you want to use `errorPolicy: 'all'` as a default option for a query, you will need to register its type like this: ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { namespace ApolloClient { namespace DeclareDefaultOptions { interface WatchQuery { // possible global-registered values: // * `errorPolicy` // * `returnPartialData` errorPolicy: "all"; } interface Query { // possible global-registered values: // * `errorPolicy` } interface Mutate { // possible global-registered values: // * `errorPolicy` } } } } ``` Once this type declaration is in place, the type of `result.data` in the above example will correctly be changed to `TData | undefined`, reflecting the possibility that if an error occurs, `data` might be `undefined`. Manually specifying `useSuspenseQuery(MY_QUERY, { errorPolicy: "none" });` changes `result.data` to `TData` to reflect the local override. This change means that you will need to declare your default options types in order to use `defaultOptions` with `ApolloClient`, otherwise you will see a TypeScript error. Without the type declaration, the following (previously valid) code will now error: ```ts new ApolloClient({ link: ApolloLink.empty(), cache: new InMemoryCache(), defaultOptions: { watchQuery: { // results in a type error: // Type '"all"' is not assignable to type '"A default option for watchQuery.errorPolicy must be declared in ApolloClient.DeclareDefaultOptions before usage. See https://www.apollographql.com/docs/react/data/typescript#declaring-default-options-for-type-safety."'. errorPolicy: "all", }, }, }); ``` If you are creating multiple instances of Apollo Client with conflicting default options and you cannot register a single `defaultOptions` value as a result, you can relax the constraints by declaring those options as union types covering all values used by all clients. The properties can be required (to enforce them in `defaultOptions`) or optional (if some constructor calls won't pass a value): ```ts // apollo.d.ts import "@apollo/client"; declare module "@apollo/client" { export namespace ApolloClient { export namespace DeclareDefaultOptions { interface WatchQuery { errorPolicy?: "none" | "all" | "ignore"; returnPartialData?: boolean; } interface Query { errorPolicy?: "none" | "all" | "ignore"; } interface Mutate { errorPolicy?: "none" | "all" | "ignore"; } } } } ``` With this declaration, the `ApolloClient` constructor accepts any of those values in `defaultOptions`. The tradeoff is that hook and method return types become more generic. For example, calling `useSuspenseQuery` without an explicit `errorPolicy` will return a result typed as if all error policies are possible, since TypeScript can't know which specific value your instance uses at runtime. Note that making a property optional (`errorPolicy?:`) is equivalent to adding the TypeScript default value (`"none"`) to the union. So `errorPolicy?: "all" | "ignore"` has the same effect on return types as `errorPolicy: "none" | "all" | "ignore"`, because TypeScript assumes the option could also be absent (i.e., `"none"`). You can also use a **partial union** that only lists the values you actually use. For example, if you only ever use `"all"` or `"ignore"`, declare `errorPolicy: "all" | "ignore"` (required) to keep the union narrow and avoid unused values broadening your signatures unnecessarily. ## 4.2.0-alpha.1 ### Patch Changes - [#13166](https://github.com/apollographql/apollo-client/pull/13166) [`0537d97`](https://github.com/apollographql/apollo-client/commit/0537d97161a51479141a182d869458912e1b8e1d) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Release changes in 4.1.5 and 4.1.6. ## 4.2.0-alpha.0 ### Minor Changes - [#13130](https://github.com/apollographql/apollo-client/pull/13130) [`dd12231`](https://github.com/apollographql/apollo-client/commit/dd122316028b55307de4a40335512307c8fa916a) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Improve the accuracy of `client.query` return type to better detect the current `errorPolicy`. The `data` property is no longer nullable when the `errorPolicy` is `none`. This makes it possible to remove the `undefined` checks or optional chaining in most cases. ## 4.1.9 ### Patch Changes - [#13203](https://github.com/apollographql/apollo-client/pull/13203) [`099954b`](https://github.com/apollographql/apollo-client/commit/099954b9905c0f80b57563eb64157386f4493e84) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Remove the `workspaces` field from the published `package.json` in `dist` to avoid Yarn v1 warnings about workspaces requiring private packages. ## 4.1.8 ### Patch Changes - [#13202](https://github.com/apollographql/apollo-client/pull/13202) [`8a51ea6`](https://github.com/apollographql/apollo-client/commit/8a51ea636600dbe4b48477d32f30469b7d36b152) Thanks [@phryneas](https://github.com/phryneas)! - Ship agent skill for usage with @tanstack/intent — the skill is now bundled in the npm package under `skills/apollo-client/` and discoverable by `intent list`. For more context, see the [TanStack Intent QuickStart](https://tanstack.com/intent/latest/docs/getting-started/quick-start-consumers). ## 4.1.7 ### Patch Changes - [#13187](https://github.com/apollographql/apollo-client/pull/13187) [`bb3fd9b`](https://github.com/apollographql/apollo-client/commit/bb3fd9b3d40a2505add673a6ee89d85b8b4c8984) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix RxJS interop issue with the observable returned by `WebSocketLink`. ## 4.1.6 ### Patch Changes - [#13128](https://github.com/apollographql/apollo-client/pull/13128) [`6c0b8e4`](https://github.com/apollographql/apollo-client/commit/6c0b8e4301609b62ed599340589c978e4f51f020) Thanks [@pavelivanov](https://github.com/pavelivanov)! - Fix `useQuery` hydration mismatch when `ssr: false` and `skip: true` are used together When both options were combined, the server would return `loading: false` (because `useSSRQuery` checks `skip` first), but the client's `getServerSnapshot` was returning `ssrDisabledResult` with `loading: true`, causing a hydration mismatch. ## 4.1.5 ### Patch Changes - [#13155](https://github.com/apollographql/apollo-client/pull/13155) [`3ba1583`](https://github.com/apollographql/apollo-client/commit/3ba1583f93c40343501acd9d598ce506537d1c9b) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix an issue where `useQuery` would poll with `pollInterval` when `skip` was initialized to `true`. - [#13135](https://github.com/apollographql/apollo-client/pull/13135) [`fd42142`](https://github.com/apollographql/apollo-client/commit/fd42142495d24859a9bc7145a85bc8f8d857ec88) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix issue where `client.query` would apply options from `defaultOptions.watchQuery`. ## 4.1.4 ### Patch Changes - [#13124](https://github.com/apollographql/apollo-client/pull/13124) [`578081f`](https://github.com/apollographql/apollo-client/commit/578081f2da7f2f54c0dd2711ee4a97530a5c38fc) Thanks [@Re-cool](https://github.com/Re-cool)! - Ensure `PersistedQueryLink` merges `http` and `fetchOptions` context values instead of overwriting them. ## 4.1.3 ### Patch Changes - [#13111](https://github.com/apollographql/apollo-client/pull/13111) [`bf46fe0`](https://github.com/apollographql/apollo-client/commit/bf46fe019b316ea8a87a05981a89fac5411260b4) Thanks [@RogerHYang](https://github.com/RogerHYang)! - Fix `createFetchMultipartSubscription` to support cancellation via `AbortController` Previously, calling `dispose()` or `unsubscribe()` on a subscription created by `createFetchMultipartSubscription` had no effect - the underlying fetch request would continue running until completion. This was because no `AbortController` was created or passed to `fetch()`, and no cleanup function was returned from the Observable. ## 4.1.2 ### Patch Changes - [#13105](https://github.com/apollographql/apollo-client/pull/13105) [`8b62263`](https://github.com/apollographql/apollo-client/commit/8b62263e19b3442e20fea822de62074cf4f5cb22) Thanks [@phryneas](https://github.com/phryneas)! - `ssrMode`, `ssrForceFetchDelay` or `prioritizeCacheValues` should not override `fetchPolicy: 'cache-only'`, `fetchPolicy: 'no-cache'`, `fetchPolicy: 'standby'`, `skip: true`, or `skipToken` when reading the initial value of an `ObservableQuery`. - [#13105](https://github.com/apollographql/apollo-client/pull/13105) [`8b62263`](https://github.com/apollographql/apollo-client/commit/8b62263e19b3442e20fea822de62074cf4f5cb22) Thanks [@phryneas](https://github.com/phryneas)! - Fix `skipToken` in `useQuery` with `prerenderStatic` and related SSR functions. - [#13105](https://github.com/apollographql/apollo-client/pull/13105) [`8b62263`](https://github.com/apollographql/apollo-client/commit/8b62263e19b3442e20fea822de62074cf4f5cb22) Thanks [@phryneas](https://github.com/phryneas)! - Avoid fetches with `fetchPolicy: no-cache` in `useQuery` with `prerenderStatic` and related SSR functions. ## 4.1.1 ### Patch Changes - [#13103](https://github.com/apollographql/apollo-client/pull/13103) [`dee7dcf`](https://github.com/apollographql/apollo-client/commit/dee7dcff4d4baa26d623d1ecace60be88c684c1a) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Ensure `@client` fields that are children of aliased server fields are resolved correctly. ## 4.1.0 ### Minor Changes - [#13043](https://github.com/apollographql/apollo-client/pull/13043) [`65e66ca`](https://github.com/apollographql/apollo-client/commit/65e66cafb6828b63d14b64877bbad47af95f66e4) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Support `headers` transport for enhanced client awareness. - [#12927](https://github.com/apollographql/apollo-client/pull/12927) [`785e223`](https://github.com/apollographql/apollo-client/commit/785e2232b4f7d9e561611cd4f45b8fdd1e44319e) Thanks [@jerelmiller](https://github.com/jerelmiller)! - You can now provide a callback function as the `context` option on the `mutate` function returned by `useMutation`. The callback function is called with the value of the `context` option provided to the `useMutation` hook. This is useful if you'd like to merge the context object provided to the `useMutation` hook with a value provided to the `mutate` function. ```ts function MyComponent() { const [mutate, result] = useMutation(MUTATION, { context: { foo: true }, }); async function runMutation() { await mutate({ // sends context as { foo: true, bar: true } context: (hookContext) => ({ ...hookContext, bar: true }), }); } // ... } ``` - [#12923](https://github.com/apollographql/apollo-client/pull/12923) [`94ea3e3`](https://github.com/apollographql/apollo-client/commit/94ea3e32c82dd767b62a6907be6c3891864633af) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Fix an issue where deferred payloads that returned arrays with fewer items than the original cached array would retain items from the cached array. This change includes `@stream` arrays where stream arrays replace the cached arrays. - [#12927](https://github.com/apollographql/apollo-client/pull/12927) [`96b531f`](https://github.com/apollographql/apollo-client/commit/96b531f6b57a158aa2c57da976c6dd22c1a7f4d5) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Don't set the fallback value of a `@client` field to `null` when a `read` function is defined. Instead the `read` function will be called with an `existing` value of `undefined` to allow default arguments to be used to set the returned value. When a `read` function is not defined nor is there a defined resolver for the field, warn and set the value to `null` only in that instance. - [#12927](https: