#12066 c01da5d
Thanks @jerelmiller! - Adds a new useSuspenseFragment
hook.
useSuspenseFragment
suspends until data
is complete. It is a drop-in replacement for useFragment
when you prefer to use Suspense to control the loading state of a fragment. See the documentation for more details.
#12174 ba5cc33
Thanks @jerelmiller! - Ensure errors thrown in the onCompleted
callback from useMutation
don't call onError
.
#12340 716d02e
Thanks @phryneas! - Deprecate the onCompleted
and onError
callbacks of useQuery
and useLazyQuery
.
For more context, please see the related issue on GitHub.
#12276 670f112
Thanks @Cellule! - Provide a more type-safe option for the previous data value passed to observableQuery.updateQuery
. Using it could result in crashes at runtime as this callback could be called with partial data even though its type reported the value as a complete result.
The updateQuery
callback function is now called with a new type-safe previousData
property and a new complete
property in the 2nd argument that determines whether previousData
is a complete or partial result.
As a result of this change, it is recommended to use the previousData
property passed to the 2nd argument of the callback rather than using the previous data value from the first argument since that value is not type-safe. The first argument is now deprecated and will be removed in a future version of Apollo Client.
observableQuery.updateQuery(
(unsafePreviousData, { previousData, complete }) => {
previousData;
// ^? TData | DeepPartial<TData> | undefined
if (complete) {
previousData;
// ^? TData
} else {
previousData;
// ^? DeepPartial<TData> | undefined
}
}
);
#12174 ba5cc33
Thanks @jerelmiller! - Reject the mutation promise if errors are thrown in the onCompleted
callback of useMutation
.
#12066 c01da5d
Thanks @jerelmiller! - Adds a new useSuspenseFragment
hook.
useSuspenseFragment
suspends until data
is complete. It is a drop-in replacement for useFragment
when you prefer to use Suspense to control the loading state of a fragment.
#12174 ba5cc33
Thanks @jerelmiller! - Ensure errors thrown in the onCompleted
callback from useMutation
don't call onError
.
#12340 716d02e
Thanks @phryneas! - Deprecate the onCompleted
and onError
callbacks of useQuery
and useLazyQuery
.
For more context, please see the related issue on GitHub.
#12276 670f112
Thanks @Cellule! - Provide a more type-safe option for the previous data value passed to observableQuery.updateQuery
. Using it could result in crashes at runtime as this callback could be called with partial data even though its type reported the value as a complete result.
The updateQuery
callback function is now called with a new type-safe previousData
property and a new complete
property in the 2nd argument that determines whether previousData
is a complete or partial result.
As a result of this change, it is recommended to use the previousData
property passed to the 2nd argument of the callback rather than using the previous data value from the first argument since that value is not type-safe. The first argument is now deprecated and will be removed in a future version of Apollo Client.
observableQuery.updateQuery(
(unsafePreviousData, { previousData, complete }) => {
previousData;
// ^? TData | DeepPartial<TData> | undefined
if (complete) {
previousData;
// ^? TData
} else {
previousData;
// ^? DeepPartial<TData> | undefined
}
}
);
#12174 ba5cc33
Thanks @jerelmiller! - Reject the mutation promise if errors are thrown in the onCompleted
callback of useMutation
.
#12252 cb9cd4e
Thanks @jerelmiller! - Changes the default behavior of the MaybeMasked
type to preserve types unless otherwise specified. This change makes it easier to upgrade from older versions of the client where types could have unexpectedly changed in the application due to the default of trying to unwrap types into unmasked types. This change also fixes the compilation performance regression experienced when simply upgrading the client since types are now preserved by default.
A new mode
option has now been introduced to allow for the old behavior. See the next section on migrating if you wish to maintain the old default behavior after upgrading to this version.
Migrating from <= v3.12.4
If you've adopted data masking and have opted in to using masked types by setting the enabled
property to true
, you can remove this configuration entirely:
-declare module "@apollo/client" {
- interface DataMasking {
- mode: "unmask"
- }
-}
If you prefer to specify the behavior explicitly, change the property from enabled: true
, to mode: "preserveTypes"
:
declare module "@apollo/client" {
interface DataMasking {
- enabled: true
+ mode: "preserveTypes"
}
}
If you rely on the default behavior in 3.12.4 or below and would like to continue to use unmasked types by default, set the mode
to unmask
:
declare module "@apollo/client" {
interface DataMasking {
mode: "unmask";
}
}
#11789 5793301
Thanks @phryneas! - Changes usages of the GraphQLError
type to GraphQLFormattedError
.
This was a type bug - these errors were never GraphQLError
instances
to begin with, and the GraphQLError
class has additional properties that can
never be correctly rehydrated from a GraphQL result.
The correct type to use here is GraphQLFormattedError
.
Similarly, please ensure to use the type FormattedExecutionResult
instead of ExecutionResult
- the non-"Formatted" versions of these types
are for use on the server only, but don't get transported over the network.
#11626 228429a
Thanks @phryneas! - Call nextFetchPolicy
with "variables-changed" even if there is a fetchPolicy
specified.
Previously this would only be called when the current fetchPolicy
was equal to the fetchPolicy
option or the option was not specified. If you use nextFetchPolicy
as a function, expect to see this function called more often.
Due to this bug, this also meant that the fetchPolicy
might be reset to the initial fetchPolicy
, even when you specified a nextFetchPolicy
function. If you previously relied on this behavior, you will need to update your nextFetchPolicy
callback function to implement this resetting behavior.
As an example, if your code looked like the following:
useQuery(QUERY, {
nextFetchPolicy(currentFetchPolicy, info) {
// your logic here
}
);
Update your function to the following to reimplement the resetting behavior:
useQuery(QUERY, {
nextFetchPolicy(currentFetchPolicy, info) {
if (info.reason === 'variables-changed') {
return info.initialFetchPolicy;
}
// your logic here
}
);
#11923 d88c7f8
Thanks @jerelmiller! - Add support for subscribeToMore
function to useQueryRefHandlers
.
#11854 3812800
Thanks @jcostello-atlassian! - Support extensions in useSubscription
#11923 d88c7f8
Thanks @jerelmiller! - Add support for subscribeToMore
function to useLoadableQuery
.
#11863 98e44f7
Thanks @phryneas! - Reimplement useSubscription
to fix rules of React violations.
#11869 a69327c
Thanks @phryneas! - Rewrite big parts of useQuery
and useLazyQuery
to be more compliant with the Rules of React and React Compiler
#11936 1b23337
Thanks @jerelmiller! - Add the ability to specify a name for the client instance for use with Apollo Client Devtools. This is useful when instantiating multiple clients to identify the client instance more easily. This deprecates the connectToDevtools
option in favor of a new devtools
configuration.
new ApolloClient({
devtools: {
enabled: true,
name: "Test Client",
},
});
This option is backwards-compatible with connectToDevtools
and will be used in the absense of a devtools
option.
#11923 d88c7f8
Thanks @jerelmiller! - Add support for subscribeToMore
function to useBackgroundQuery
.
#11789 5793301
Thanks @phryneas! - Changes usages of the GraphQLError
type to GraphQLFormattedError
.
This was a type bug - these errors were never GraphQLError
instances
to begin with, and the GraphQLError
class has additional properties that can
never be correctly rehydrated from a GraphQL result.
The correct type to use here is GraphQLFormattedError
.
Similarly, please ensure to use the type FormattedExecutionResult
instead of ExecutionResult
- the non-"Formatted" versions of these types
are for use on the server only, but don't get transported over the network.
#11930 a768575
Thanks @jerelmiller! - Deprecates experimental schema testing utilities introduced in 3.10 in favor of recommending @apollo/graphql-testing-library
.
#11888 7fb7939
Thanks @phryneas! - switch useRenderGuard
to an approach not accessing React's internals
#11511 6536369
Thanks @phryneas! - useLoadableQuery
: ensure that loadQuery
is updated if the ApolloClient instance changes
#11860 8740f19
Thanks @alessbell! - Fixes #11849 by reevaluating window.fetch
each time BatchHttpLink
uses it, if not configured via options.fetch
. Takes the same approach as PR #8603 which fixed the same issue in HttpLink
.
#11852 d502a69
Thanks @phryneas! - Fix a bug where calling the useMutation
reset
function would point the hook to an outdated client
reference.
#11329 3d164ea
Thanks @PaLy! - Fix graphQLErrors in Error Link if networkError.result is an empty string
#11852 d502a69
Thanks @phryneas! - Prevent writing to a ref in render in useMutation
.
As a result, you might encounter problems in the future if you call the mutation's execute
function during render. Please note that this was never supported behavior, and we strongly recommend against it.
#11848 ad63924
Thanks @phryneas! - Ensure covariant behavior: MockedResponse<X,Y>
should be assignable to MockedResponse
#11851 45c47be
Thanks @phryneas! - Avoid usage of useRef in useInternalState to prevent ref access in render.
#11877 634d91a
Thanks @phryneas! - Add missing name to tuple member (fix TS5084)
#11851 45c47be
Thanks @phryneas! - Fix a bug where useLazyQuery
would not pick up a client change.
#11838 8475346
Thanks @alex-kinokon! - Don’t prompt for DevTools installation for browser extension page
#11839 6481fe1
Thanks @jerelmiller! - Fix a regression in 3.9.5 where a merge function that returned an incomplete result would not allow the client to refetch in order to fulfill the query.
#11844 86984f2
Thanks @jerelmiller! - Honor the @nonreactive
directive when using cache.watchFragment
or the useFragment
hook to avoid rerendering when using these directives.
#11824 47ad806
Thanks @phryneas! - Create branded QueryRef
type without exposed properties.
This change deprecates QueryReference
in favor of a QueryRef
type that doesn't expose any properties.
This change also updates preloadQuery
to return a new PreloadedQueryRef
type, which exposes the toPromise
function as it does today. This means that query refs produced by useBackgroundQuery
and useLoadableQuery
now return QueryRef
types that do not have access to a toPromise
function, which was never meant to be used in combination with these hooks.
While we tend to avoid any types of breaking changes in patch releases as this, this change was necessary to support an upcoming version of the React Server Component integration, which needed to omit the toPromise
function that would otherwise have broken at runtime.
Note that this is a TypeScript-only change. At runtime, toPromise
is still present on all queryRefs currently created by this package - but we strongly want to discourage you from accessing it in all cases except for the PreloadedQueryRef
use case.
Migration is as simple as replacing all references to QueryReference
with QueryRef
, so it should be possible to do this with a search & replace in most code bases:
-import { QueryReference } from '@apollo/client'
+import { QueryRef } from '@apollo/client'
- function Component({ queryRef }: { queryRef: QueryReference<TData> }) {
+ function Component({ queryRef }: { queryRef: QueryRef<TData> }) {
// ...
}
#11845 4c5c820
Thanks @jerelmiller! - Remove @nonreactive
directives from queries passed to MockLink
to ensure they are properly matched.
#11837 dff15b1
Thanks @jerelmiller! - Fix an issue where a polled query created in React strict mode may not stop polling after the component unmounts while using the cache-and-network
fetch policy.
#11424 62f3b6d
Thanks @phryneas! - Simplify RetryLink, fix potential memory leak
Historically, RetryLink
would keep a values
array of all previous values, in case the operation would get an additional subscriber at a later point in time.
In practice, this could lead to a memory leak (#11393) and did not serve any further purpose, as the resulting observable would only be subscribed to by Apollo Client itself, and only once - it would be wrapped in a Concast
before being exposed to the user, and that Concast
would handle subscribers on its own.
#11435 5cce53e
Thanks @phryneas! - Deprecates canonizeResults
.
Using canonizeResults
can result in memory leaks so we generally do not recommend using this option anymore. A future version of Apollo Client will contain a similar feature without the risk of memory leaks.
#11254 d08970d
Thanks @benjamn! - Decouple canonicalStringify
from ObjectCanon
for better time and memory performance.
#11356 cc4ac7e
Thanks @phryneas! - Fix a potential memory leak in FragmentRegistry.transform
and FragmentRegistry.findFragmentSpreads
that would hold on to passed-in DocumentNodes
for too long.
#11370 25e2cb4
Thanks @phryneas! - parse
function: improve memory management
- use LRU
WeakCache
instead of Map
to keep a limited number of parsed results
- cache is initiated lazily, only when needed
- expose
parse.resetCache()
method
#11389 139acd1
Thanks @phryneas! - documentTransform
: use optimism
and WeakCache
instead of directly storing data on the Trie
#11358 7d939f8
Thanks @phryneas! - Fixes a potential memory leak in Concast
that might have been triggered when Concast
was used outside of Apollo Client.
#11344 bd26676
Thanks @phryneas! - Add a resetCache
method to DocumentTransform
and hook InMemoryCache.addTypenameTransform
up to InMemoryCache.gc
#11367 30d17bf
Thanks @phryneas! - print
: use WeakCache
instead of WeakMap
#11387 4dce867
Thanks @phryneas! - QueryManager.transformCache
: use WeakCache
instead of WeakMap
#11369 2a47164
Thanks @phryneas! - Persisted Query Link: improve memory management
- use LRU
WeakCache
instead of WeakMap
to keep a limited number of hash results
- hash cache is initiated lazily, only when needed
- expose
persistedLink.resetHashCache()
method
- reset hash cache if the upstream server reports it doesn't accept persisted queries
#10804 221dd99
Thanks @phryneas! - use WeakMap in React Native with Hermes
#11355 7d8e184
Thanks @phryneas! - InMemoryCache.gc now also triggers FragmentRegistry.resetCaches (if there is a FragmentRegistry)
#11409 2e7203b
Thanks @phryneas! - Adds an experimental ApolloClient.getMemoryInternals
helper
#11343 776631d
Thanks @phryneas! - Add reset
method to print
, hook up to InMemoryCache.gc
#10323 64cb88a4b
Thanks @jerelmiller! - Add support for React suspense with a new useSuspenseQuery
hook.
useSuspenseQuery
initiates a network request and causes the component calling it to suspend while the request is in flight. It can be thought of as a drop-in replacement for useQuery
that allows you to take advantage of React's concurrent features while fetching during render.
Consider a Dog
component that fetches and renders some information about a dog named Mozzarella:
<summary>View code 🐶</summary>
tsx
import { Suspense } from "react";
import { gql, TypedDocumentNode, useSuspenseQuery } from "@apollo/client";
interface Data {
dog: {
id: string;
name: string;
};
}
interface Variables {
name: string;
}
const GET_DOG_QUERY: TypedDocumentNode<Data, Variables> = gql`
query GetDog($name: String) {
dog(name: $name) {
id
name
}
}
`;
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dog name="Mozzarella" />
</Suspense>
);
}
function Dog({ name }: { name: string }) {
const { data } = useSuspenseQuery(GET_DOG_QUERY, {
variables: { name },
});
return <>Name: {data.dog.name}</>;
}
For a detailed explanation of useSuspenseQuery
, see our fetching with Suspense reference.
#10755 e3c676deb
Thanks @alessbell! - Feature: adds useBackgroundQuery
and useReadQuery
hooks
useBackgroundQuery
initiates a request for data in a parent component and returns a QueryReference
which is used to read the data in a child component via useReadQuery
. If the child component attempts to render before the data can be found in the cache, the child component will suspend until the data is available. On cache updates to watched data, the child component calling useReadQuery
will re-render with new data but the parent component will not re-render (as it would, for example, if it were using useQuery
to issue the request).
Consider an App
component that fetches a list of breeds in the background while also fetching and rendering some information about an individual dog, Mozzarella:
<summary>View code 🐶</summary>
tsx
function App() {
const [queryRef] = useBackgroundQuery(GET_BREEDS_QUERY);
return (
<Suspense fallback={<div>Loading...</div>}>
<Dog name="Mozzarella" queryRef={queryRef} />
</Suspense>
);
}
function Dog({
name,
queryRef,
}: {
name: string;
queryRef: QueryReference<BreedData>;
}) {
const { data } = useSuspenseQuery(GET_DOG_QUERY, {
variables: { name },
});
return (
<>
Name: {data.dog.name}
<Suspense fallback={<div>Loading breeds...</div>}>
<Breeds queryRef={queryRef} />
</Suspense>
</>
);
}
function Breeds({ queryRef }: { queryRef: QueryReference<BreedData> }) {
const { data } = useReadQuery(queryRef);
return data.breeds.map(({ characteristics }) =>
characteristics.map((characteristic) => (
<div key={characteristic}>{characteristic}</div>
))
);
}
For a detailed explanation of useBackgroundQuery
and useReadQuery
, see our fetching with Suspense reference.
#10470 47435e879
Thanks @alessbell! - Bumps TypeScript to 4.9.4
(previously 4.7.4
) and updates types to account for changes in TypeScript 4.8 by propagating contstraints on generic types. Technically this makes some types stricter as attempting to pass null|undefined
into certain functions is now disallowed by TypeScript, but these were never expected runtime values in the first place.
This should only affect you if you are wrapping functions provided by Apollo Client with your own abstractions that pass in their generics as type arguments, in which case you might get an error like error TS2344: Type 'YourGenericType' does not satisfy the constraint 'OperationVariables'
. In that case, make sure that YourGenericType
is restricted to a type that only accepts objects via extends
, like Record<string, any>
or @apollo/client
's OperationVariables
:
import {
QueryHookOptions,
QueryResult,
useQuery,
+ OperationVariables,
} from '@apollo/client';
- export function useWrappedQuery<T, TVariables>(
+ export function useWrappedQuery<T, TVariables extends OperationVariables>(
query: DocumentNode,
queryOptions: QueryHookOptions<T, TVariables>
): QueryResult<T, TVariables> {
const [execute, result] = useQuery<T, TVariables>(query);
}
#10408 55ffafc58
Thanks @zlrlo! - fix: modify BatchHttpLink to have a separate timer for each different batch key
#9573 4a4f48dda
Thanks @vladar! - Improve performance of local resolvers by only executing selection sets that contain an @client
directive. Previously, local resolvers were executed even when the field did not contain @client
. While the result was properly discarded, the unncessary work could negatively affect query performance, sometimes signficantly.
In upcoming v3.6.x and v3.7 (beta) releases, we will be completely overhauling our server-side rendering utilities (getDataFromTree
et al.), and introducing suspenseful versions of our hooks, to take full advantage of the new patterns React 18+ enables for data management libraries like Apollo Client.
Add updateQuery
and updateFragment
methods to ApolloCache
, simplifying common readQuery
/writeQuery
cache update patterns.
@wassim-k in #8382
Field directives and their arguments can now be included along with field argument names when using field policy keyArgs: [...]
notation. For example, if you have a Query.feed
field that takes an argument called type
and uses a @connection(key:...)
directive to keep feed
data from different queries separate within the cache, you might configure both using the following InMemoryCache
field policy:
new InMemoryCache({
typePolicies: {
Query: {
fields: {
feed: {
keyArgs: ["type", "@connection", ["key"]],
},
},
},
},
});
@benjamn in #8678
Report single MissingFieldError
instead of a potentially very large MissingFieldError[]
array for incomplete cache reads, improving performance and memory usage.
@benjamn in #8734
When writing results into InMemoryCache
, each written object is now identified using policies.identify
after traversing the fields of the object (rather than before), simplifying identification and reducing duplicate work. If you have custom keyFields
functions, they still receive the raw result object as their first parameter, but the KeyFieldsContext
parameter now provides context.storeObject
(the StoreObject
just processed by processSelectionSet
) and context.readField
(a helper function for reading fields from context.storeObject
and any Reference
s it might contain, similar to readField
for read
, merge
, and cache.modify
functions).
@benjamn in #8996
Ensure cache.identify
never throws when primary key fields are missing, and include the source object in the error message when keyFields
processing fails.
@benjamn in #8679
The HttpLink
constructor now accepts an optional print
function that can be used to customize how GraphQL DocumentNode
objects are transformed back into strings before they are sent over the network.
@sarahgp in #8699
Make @apollo/client/testing
a fully-fledged, independent entry point, instead of re-exporting @apollo/client/utilities/testing
(which was never an entry point and no longer exists).
@benjamn in #8769
A new nested entry point called @apollo/client/testing/core
has been created. Importing from this entry point instead of @apollo/client/testing
excludes any React-related dependencies.
@wassim-k in #8687
Make cache.batch
return the result of calling the options.update
function.
@benjamn in #8696
The NetworkError
and ErrorResponse
types have been changed to align more closely.
@korywka in #8424
Include graphql@16
in peer deps.
@brainkim in #8997
Update zen-observable-ts
to eliminate transitive dependency on @types/zen-observable
.
@benjamn in #8695
InMemoryCache
now guarantees that any two result objects returned by the cache (from readQuery
, readFragment
, etc.) will be referentially equal (===
) if they are deeply equal. Previously, ===
equality was often achievable for results for the same query, on a best-effort basis. Now, equivalent result objects will be automatically shared among the result trees of completely different queries. This guarantee is important for taking full advantage of optimistic updates that correctly guess the final data, and for "pure" UI components that can skip re-rendering when their input data are unchanged.
@benjamn in #7439
Mutations now accept an optional callback function called onQueryUpdated
, which will be passed the ObservableQuery
and Cache.DiffResult
objects for any queries invalidated by cache writes performed by the mutation's final update
function. Using onQueryUpdated
, you can override the default FetchPolicy
of the query, by (for example) calling ObservableQuery
methods like refetch
to force a network request. This automatic detection of invalidated queries provides an alternative to manually enumerating queries using the refetchQueries
mutation option. Also, if you return a Promise
from onQueryUpdated
, the mutation will automatically await that Promise
, rendering the awaitRefetchQueries
option unnecessary.
@benjamn in #7827
Support client.refetchQueries
as an imperative way to refetch queries, without having to pass options.refetchQueries
to client.mutate
.
@dannycochran in #7431
Improve standalone client.refetchQueries
method to support automatic detection of queries needing to be refetched.
@benjamn in #8000
Fix remaining barriers to loading @apollo/client/core
as native ECMAScript modules from a CDN like esm.run. Importing @apollo/client
from a CDN will become possible once we move all React-related dependencies into @apollo/client/react
in Apollo Client 4.
@benjamn in #8266
InMemoryCache
supports a new method called batch
, which is similar to performTransaction
but takes named options rather than positional parameters. One of these named options is an onDirty(watch, diff)
callback, which can be used to determine which watched queries were invalidated by the batch
operation.
@benjamn in #7819
Allow merge: true
field policy to merge Reference
objects with non-normalized objects, and vice-versa.
@benjamn in #7778
Allow identical subscriptions to be deduplicated by default, like queries.
@jkossis in #6910
Always use POST
request when falling back to sending full query with @apollo/client/link/persisted-queries
.
@rieset in #7456
The FetchMoreQueryOptions
type now takes two instead of three type parameters (<TVariables, TData>
), thanks to using Partial<TVariables>
instead of K extends typeof TVariables
and Pick<TVariables, K>
.
@ArnaudBarre in #7476
Pass variables
and context
to a mutation's update
function. Note: The type of the update
function is now named MutationUpdaterFunction
rather than MutationUpdaterFn
, since the older type was broken beyond repair. If you are using MutationUpdaterFn
in your own code, please use MutationUpdaterFunction
instead.
@jcreighton in #7902
A resultCacheMaxSize
option may be passed to the InMemoryCache
constructor to limit the number of result objects that will be retained in memory (to speed up repeated reads), and calling cache.reset()
now releases all such memory.
@SofianHn in #8107
Fully remove result cache entries from LRU dependency system when the corresponding entities are removed from InMemoryCache
by eviction, or by any other means.
@sofianhn and @benjamn in #8147
Expose missing field errors in results.
@brainkim in #8262
Add expected/received variables
to No more mocked responses...
error messages generated by MockLink
.
@markneub in #8340
The InMemoryCache
version of the cache.gc
method now supports additional options for removing non-essential (recomputable) result caching data.
@benjamn in #8421
Suppress noisy Missing cache result fields...
warnings by default unless setLogVerbosity("debug")
called.
@benjamn in #8489
Improve interaction between React hooks and React Fast Refresh in development.
@andreialecu in #7952
To avoid retaining sensitive information from mutation root field arguments, Apollo Client v3.4 automatically clears any ROOT_MUTATION
fields from the cache after each mutation finishes. If you need this information to remain in the cache, you can prevent the removal by passing the keepRootFields: true
option to client.mutate
. ROOT_MUTATION
result data are also passed to the mutation update
function, so we recommend obtaining the results that way, rather than using keepRootFields: true
, if possible.
@benjamn in #8280
Internally, Apollo Client now controls the execution of development-only code using the __DEV__
global variable, rather than process.env.NODE_ENV
. While this change should not cause any visible differences in behavior, it will increase your minified+gzip bundle size by more than 3.5kB, unless you configure your minifier to replace __DEV__
with a true
or false
constant, the same way you already replace process.env.NODE_ENV
with a string literal like "development"
or "production"
. For an example of configuring a Create React App project without ejecting, see this pull request for our React Apollo reproduction template.
@benjamn in #8347
Internally, Apollo Client now uses namespace syntax (e.g. import * as React from "react"
) for imports whose types are re-exported (and thus may appear in .d.ts
files). This change should remove any need to configure esModuleInterop
or allowSyntheticDefaultImports
in tsconfig.json
, but might require updating bundler configurations that specify named exports of the react
and prop-types
packages, to include exports like createContext
and createElement
(example).
@devrelm in #7742
Respect no-cache
fetch policy (by not reading any data
from the cache) for loading: true
results triggered by notifyOnNetworkStatusChange: true
.
@jcreighton in #7761
The TypeScript return types of the getLastResult
and getLastError
methods of ObservableQuery
now correctly include the possibility of returning undefined
. If you happen to be calling either of these methods directly, you may need to adjust how the calling code handles the methods' possibly-undefined
results.
@benjamn in #8394
Log non-fatal invariant.error
message when fields are missing from result objects written into InMemoryCache
, rather than throwing an exception. While this change relaxes an exception to be merely an error message, which is usually a backwards-compatible change, the error messages are logged in more cases now than the exception was previously thrown, and those new error messages may be worth investigating to discover potential problems in your application. The errors are not displayed for @client
-only fields, so adding @client
is one way to handle/hide the errors for local-only fields. Another general strategy is to use a more precise query to write specific subsets of data into the cache, rather than reusing a larger query that contains fields not present in the written data
.
@benjamn in #8416
The nextFetchPolicy
option for client.watchQuery
and useQuery
will no longer be removed from the options
object after it has been applied, and instead will continue to be applied any time options.fetchPolicy
is reset to another value, until/unless the options.nextFetchPolicy
property is removed from options
.
@benjamn in #8465
The fetchMore
, subscribeToMore
, and updateQuery
functions returned from the useQuery
hook may now return undefined in edge cases where the functions are called when the component is unmounted
@noghartt in #7980.
In Apollo Client 2.x, a refetch
operation would always replace existing data in the cache. With the introduction of field policy merge
functions in Apollo Client 3, existing field values could be inappropriately combined with incoming field values by a custom merge
function that does not realize a refetch
has happened.
To give you more control over this behavior, we have introduced an overwrite?: boolean = false
option for cache.writeQuery
and cache.writeFragment
, and an option called refetchWritePolicy?: "merge" | "overwrite"
for client.watchQuery
, useQuery
, and other functions that accept WatchQueryOptions
. You can use these options to make sure any merge
functions involved in cache writes for refetch
operations get invoked with undefined
as their first argument, which simulates the absence of any existing data, while still giving the merge
function a chance to determine the internal representation of the incoming data.
The default behaviors are overwrite: true
and refetchWritePolicy: "overwrite"
, which restores the Apollo Client 2.x behavior, but (if this change causes any problems for your application) you can easily recover the previous merging behavior by setting a default value for refetchWritePolicy
in defaultOptions.watchQuery
:
new ApolloClient({
defaultOptions: {
watchQuery: {
refetchWritePolicy: "merge",
},
},
});
@benjamn in #7810
Make sure the MockedResponse
ResultFunction
type is re-exported.
@hwillson in #8315
Fix polling when used with skip
.
@brainkim in #8346
InMemoryCache
now coalesces EntityStore
updates to guarantee only one store.merge(id, fields)
call per id
per cache write.
@benjamn in #8372
Fix polling when used with <React.StrictMode>
.
@brainkim in #8414
Fix the React integration logging Warning: Can't perform a React state update on an unmounted component
.
@wuarmin in #7745
Make ObservableQuery#getCurrentResult
always call queryInfo.getDiff()
.
@benjamn in #8422
Make readField
default to reading from current object only when the from
option/argument is actually omitted, not when from
is passed to readField
with an undefined value. A warning will be printed when this situation occurs.
@benjamn in #8508
The fetchMore
, subscribeToMore
, and updateQuery
functions no longer throw undefined
errors
@noghartt in #7980.
Ensure cache.readQuery
and cache.readFragment
always return TData | null
, instead of throwing MissingFieldError
exceptions when missing fields are encountered.
@benjamn in #7098
Since this change converts prior exceptions to null
returns, and since null
was already a possible return value according to the TData | null
return type, we are confident this change will be backwards compatible (as long as null
was properly handled before).
HttpLink
will now automatically strip any unused variables
before sending queries to the GraphQL server, since those queries are very likely to fail validation, according to the All Variables Used rule in the GraphQL specification. If you depend on the preservation of unused variables, you can restore the previous behavior by passing includeUnusedVariables: true
to the HttpLink
constructor (which is typically passed as options.link
to the ApolloClient
constructor).
@benjamn in #7127
Ensure MockLink
(used by MockedProvider
) returns mock configuration errors (e.g. No more mocked responses for the query ...
) through the Link's Observable
, instead of throwing them. These errors are now available through the error
property of a result.
@hwillson in #7110
Returning mock configuration errors through the Link's Observable
was the default behavior in Apollo Client 2.x. We changed it for 3, but the change has been problematic for those looking to migrate from 2.x to 3. We've decided to change this back with the understanding that not many people want or are relying on MockLink
's throwing exception approach. If you want to change this functionality, you can define custom error handling through MockLink.setOnError
.
Unsubscribing the last observer from an ObservableQuery
will once again unsubscribe from the underlying network Observable
in all cases, as in Apollo Client 2.x, allowing network requests to be cancelled by unsubscribing.
@javier-garcia-meteologica in #7165 and #7170.
The independent QueryBaseOptions
and ModifiableWatchQueryOptions
interface supertypes have been eliminated, and their fields are now defined by QueryOptions
.
@DCtheTall in #7136
Internally, Apollo Client now avoids nested imports from the graphql
package, importing everything from the top-level package instead. For example,
import { visit } from "graphql/language/visitor";
is now just
import { visit } from "graphql";
Since the graphql
package uses .mjs
modules, your bundler may need to be configured to recognize .mjs
files as ECMAScript modules rather than CommonJS modules.
@benjamn in #7185
Support inheritance of type and field policies, according to possibleTypes
.
@benjamn in #7065
Allow configuring custom merge
functions, including the merge: true
and merge: false
shorthands, in type policies as well as field policies.
@benjamn in #7070
The verbosity of Apollo Client console messages can be globally adjusted using the setLogVerbosity
function:
import { setLogVerbosity } from "@apollo/client";
setLogVerbosity("log"); // display all messages
setLogVerbosity("warn"); // display only warnings and errors (default)
setLogVerbosity("error"); // display only errors
setLogVerbosity("silent"); // hide all console messages
Remember that all logs, warnings, and errors are hidden in production.
@benjamn in #7226
Modifying InMemoryCache
fields that have keyArgs
configured will now invalidate only the field value with matching key arguments, rather than invalidating all field values that share the same field name. If keyArgs
has not been configured, the cache must err on the side of invalidating by field name, as before.
@benjamn in #7351
Shallow-merge options.variables
when combining existing or default options with newly-provided options, so new variables do not completely overwrite existing variables.
@amannn in #6927
Avoid displaying Cache data may be lost...
warnings for scalar field values that happen to be objects, such as JSON data.
@benjamn in #7075
In addition to the result.data
property, useQuery
and useLazyQuery
will now provide a result.previousData
property, which can be useful when a network request is pending and result.data
is undefined, since result.previousData
can be rendered instead of rendering an empty/loading state.
@hwillson in #7082
Passing validate: true
to the SchemaLink
constructor will enable validation of incoming queries against the local schema before execution, returning validation errors in result.errors
, just like a non-local GraphQL endpoint typically would.
@amannn in #7094
Allow optional arguments in keyArgs: [...]
arrays for InMemoryCache
field policies.
@benjamn in #7109
Avoid registering QueryPromise
when skip
is true
during server-side rendering.
@izumin5210 in #7310
ApolloCache
objects (including InMemoryCache
) may now be associated with or disassociated from individual reactive variables by calling reactiveVar.attachCache(cache)
and/or reactiveVar.forgetCache(cache)
.
@benjamn in #7350
In TypeScript, all APIs that take DocumentNode
parameters now may alternatively take TypeDocumentNode<Data, Variables>
. This type has the same JavaScript representation but allows the APIs to infer the data and variable types instead of requiring you to specify types explicitly at the call site.
@dotansimha in #6720
Bring back an improved form of heuristic fragment matching, by allowing possibleTypes
to specify subtype regular expression strings, which count as matches if the written result object has all the fields expected for the fragment.
@benjamn in #6901
Allow options.nextFetchPolicy
to be a function that takes the current FetchPolicy
and returns a new (or the same) FetchPolicy
, making nextFetchPolicy
more suitable for global use in defaultOptions.watchQuery
.
@benjamn in #6893
Implement useReactiveVar
hook for consuming reactive variables in React components.
@benjamn in #6867
Move apollo-link-persisted-queries
implementation to @apollo/client/link/persisted-queries
. Try running our automated imports transform to handle this conversion, if you're using apollo-link-persisted-queries
.
@hwillson in #6837
Disable feud-stopping logic after any cache.evict
or cache.modify
operation.
@benjamn in
#6817 and
#6898
Throw if writeFragment
cannot identify options.data
when no options.id
provided.
@jcreighton in #6859
Provide options.storage
object to cache.modify
functions, as provided to read
and merge
functions.
@benjamn in #6991
Allow cache.modify
functions to return details.INVALIDATE
(similar to details.DELETE
) to invalidate the current field, causing affected queries to rerun, even if the field's value is unchanged.
@benjamn in #6991
Support non-default ErrorPolicy
values (that is, "ignore"
and "all"
, in addition to the default value "none"
) for mutations and subscriptions, like we do for queries.
@benjamn in #7003
Remove invariant forbidding a FetchPolicy
of cache-only
in ObservableQuery#refetch
.
@benjamn in ccb0a79a, fixing #6702
[BREAKING] ApolloClient
is now only available as a named export. The default ApolloClient
export has been removed.
@hwillson in #5425
[BREAKING] The queryManager
property of ApolloClient
instances is now marked as private
, paving the way for a more aggressive redesign of its API.
[BREAKING] Apollo Client will no longer deliver "stale" results to ObservableQuery
consumers, but will instead log more helpful errors about which cache fields were missing.
@benjamn in #6058
[BREAKING] ApolloError
's thrown by Apollo Client no longer prefix error messages with GraphQL error:
or Network error:
. To differentiate between GraphQL/network errors, refer to ApolloError
's public graphQLErrors
and networkError
properties.
@lorensr in #3892
[BREAKING] Support for the @live
directive has been removed, but might be restored in the future if a more thorough implementation is proposed.
@benjamn in #6221
[BREAKING] Apollo Client 2.x allowed @client
fields to be passed into the link
chain if resolvers
were not set in the constructor. This allowed @client
fields to be passed into Links like apollo-link-state
. Apollo Client 3 enforces that @client
fields are local only, meaning they are no longer passed into the link
chain, under any circumstances.
@hwillson in #5982
[BREAKING?] Refactor QueryManager
to make better use of observables and enforce fetchPolicy
more reliably.
@benjamn in #6221
The updateQuery
function previously required by fetchMore
has been deprecated with a warning, and will be removed in the next major version of Apollo Client. Please consider using a merge
function to handle incoming data instead of relying on updateQuery
.
@benjamn in #6464
- Helper functions for generating common pagination-related field policies may be imported from
@apollo/client/utilities
. The most basic helper is concatPagination
, which emulates the concatenation behavior of typical updateQuery
functions. A more sophisticated helper is offsetLimitPagination
, which implements offset/limit-based pagination. If you are consuming paginated data from a Relay-friendly API, use relayStylePagination
. Feel free to use these helper functions as inspiration for your own field policies, and/or modify them to suit your needs.
@benjamn in #6465
Updated to work with graphql@15
.
@durchanek in #6194 and #6279
@hagmic in #6328
Apollo Link core and HTTP related functionality has been merged into @apollo/client
. Functionality that was previously available through the apollo-link
, apollo-link-http-common
and apollo-link-http
packages is now directly available from @apollo/client
(e.g. import { HttpLink } from '@apollo/client'
). The ApolloClient
constructor has also been updated to accept new uri
, headers
and credentials
options. If uri
is specified, Apollo Client will take care of creating the necessary HttpLink
behind the scenes.
@hwillson in #5412
The gql
template tag should now be imported from the @apollo/client
package, rather than the graphql-tag
package. Although the graphql-tag
package still works for now, future versions of @apollo/client
may change the implementation details of gql
without a major version bump.
@hwillson in #5451
@apollo/client/core
can be used to import the Apollo Client core, which includes everything the main @apollo/client
package does, except for all React related functionality.
@kamilkisiela in #5541
Several deprecated methods have been fully removed:
ApolloClient#initQueryManager
QueryManager#startQuery
ObservableQuery#currentResult
Apollo Client now supports setting a new ApolloLink
(or link chain) after new ApolloClient()
has been called, using the ApolloClient#setLink
method.
@hwillson in #6193
The final time a mutation update
function is called, it can no longer accidentally read optimistic data from other concurrent mutations, which ensures the use of optimistic updates has no lasting impact on the state of the cache after mutations have finished.
@benjamn in #6551
Apollo links that were previously maintained in https://github.com/apollographql/apollo-link have been merged into the Apollo Client project. They should be accessed using the new entry points listed in the migration guide.
@hwillson in #
The InMemoryCache
constructor should now be imported directly from @apollo/client
, rather than from a separate package. The apollo-cache-inmemory
package is no longer supported.
The @apollo/client/cache
entry point can be used to import InMemoryCache
without importing other parts of the Apollo Client codebase.
> @hwillson in #5577
[BREAKING] FragmentMatcher
, HeuristicFragmentMatcher
, and IntrospectionFragmentMatcher
have all been removed. We now recommend using InMemoryCache
’s possibleTypes
option instead. For more information see the Defining possibleTypes
manually section of the docs.
@benjamn in #5073
[BREAKING] As promised in the Apollo Client 2.6 blog post, all cache results are now frozen/immutable.
@benjamn in #5153
[BREAKING] Eliminate "generated" cache IDs to avoid normalizing objects with no meaningful ID, significantly reducing cache memory usage. This might be a backwards-incompatible change if your code depends on the precise internal representation of normalized data in the cache.
@benjamn in #5146
[BREAKING] InMemoryCache
will no longer merge the fields of written objects unless the objects are known to have the same identity, and the values of fields with the same name will not be recursively merged unless a custom merge
function is defined by a field policy for that field, within a type policy associated with the __typename
of the parent object.
@benjamn in #5603
[BREAKING] InMemoryCache
now throws when data with missing or undefined query fields is written into the cache, rather than just warning in development.
@benjamn in #6055
[BREAKING] client|cache.writeData
have been fully removed. writeData
usage is one of the easiest ways to turn faulty assumptions about how the cache represents data internally, into cache inconsistency and corruption. client|cache.writeQuery
, client|cache.writeFragment
, and/or cache.modify
can be used to update the cache.
@benjamn in #5923
InMemoryCache
now supports tracing garbage collection and eviction. Note that the signature of the evict
method has been simplified in a potentially backwards-incompatible way.
@benjamn in #5310
[beta-BREAKING] Please note that the cache.evict
method now requires Cache.EvictOptions
, though it previously supported positional arguments as well.
@danReynolds in #6141
@benjamn in #6364
Removing an entity object using the cache.evict
method does not automatically remove dangling references to that entity elsewhere in the cache, but dangling references will be automatically filtered from lists whenever those lists are read from the cache. You can define a custom field read
function to customize this behavior. See #6412, #6425, and #6454 for further explanation.
Cache methods that would normally trigger a broadcast, like cache.evict
, cache.writeQuery
, and cache.writeFragment
, can now be called with a named options object, which supports a broadcast: boolean
property that can be used to silence the broadcast, for situations where you want to update the cache multiple times without triggering a broadcast each time.
@benjamn in #6288
InMemoryCache
now console.warn
s in development whenever non-normalized data is dangerously overwritten, with helpful links to documentation about normalization and custom merge
functions.
@benjamn in #6372
The result caching system (introduced in #3394) now tracks dependencies at the field level, rather than at the level of whole entity objects, allowing the cache to return identical (===
) results much more often than before.
@benjamn in #5617
InMemoryCache
now has a method called modify
which can be used to update the value of a specific field within a specific entity object:
cache.modify({
id: cache.identify(post),
fields: {
comments(comments: Reference[], { readField }) {
return comments.filter(
(comment) => idToRemove !== readField("id", comment)
);
},
},
});
This API gracefully handles cases where multiple field values are associated with a single field name, and also removes the need for updating the cache by reading a query or fragment, modifying the result, and writing the modified result back into the cache. Behind the scenes, the cache.evict
method is now implemented in terms of cache.modify
.
@benjamn in #5909
and #6178
InMemoryCache
provides a new API for storing client state that can be updated from anywhere:
import { makeVar } from "@apollo/client";
const v = makeVar(123);
console.log(v()); // 123
console.log(v(v() + 1)); // 124
console.log(v()); // 124
v("asdf"); // TS type error
These variables are reactive in the sense that updating their values invalidates any previously cached query results that depended on the old values.
@benjamn in
#5799,
#5976, and
#6512
Various cache read and write performance optimizations, cutting read and write times by more than 50% in larger benchmarks.
@benjamn in #5948
The cache.readQuery
and cache.writeQuery
methods now accept an options.id
string, which eliminates most use cases for cache.readFragment
and cache.writeFragment
, and skips the implicit conversion of fragment documents to query documents performed by cache.{read,write}Fragment
.
@benjamn in #5930
Support cache.identify(entity)
for easily computing entity ID strings.
@benjamn in #5642
Support eviction of specific entity fields using cache.evict(id, fieldName)
.
@benjamn in #5643
Make InMemoryCache#evict
remove data from all EntityStore
layers.
@benjamn in #5773
Stop paying attention to previousResult
in InMemoryCache
.
@benjamn in #5644
Improve optimistic update performance by limiting cache key diversity.
@benjamn in #5648
Custom field read
functions can read from neighboring fields using the readField(fieldName)
helper, and may also read fields from other entities by calling readField(fieldName, objectOrReference)
.
@benjamn in #5651
Expose cache modify
and identify
to the mutate update
function.
@hwillson in #5956
Add a default gc
implementation to ApolloCache
.
@justinwaite in #5974
[BREAKING] The QueryOptions
, MutationOptions
, and SubscriptionOptions
React Apollo interfaces have been renamed to QueryDataOptions
, MutationDataOptions
, and SubscriptionDataOptions
(to avoid conflicting with similarly named and exported Apollo Client interfaces).
[BREAKING] Results with loading: true
will no longer redeliver previous data, though they may provide partial data from the cache, when available.
@benjamn in #6566
[BREAKING?] Remove fixPolyfills.ts
, except when bundling for React Native. If you have trouble with Map
or Set
operations due to frozen key objects in React Native, either update React Native to version 0.59.0 (or 0.61.x, if possible) or investigate why fixPolyfills.native.js
is not included in your bundle.
@benjamn in #5962
The contents of the @apollo/react-hooks
package have been merged into @apollo/client
, enabling the following all-in-one import
:
import { ApolloClient, ApolloProvider, useQuery } from "@apollo/client";
@hwillson in #5357
React SSR features (previously accessed via @apollo/react-ssr
) can now be accessed from the separate Apollo Client entry point of @apollo/client/react/ssr
. These features are not included in the default @apollo/client
bundle.
@hwillson in #6499
[BREAKING] Removed graphql-anywhere
since it's no longer used by Apollo Client.
@hwillson in #5159
[BREAKING] Removed apollo-boost
since Apollo Client 3.0 provides a boost like getting started experience out of the box.
@hwillson in #5217
[BREAKING] We are no longer exporting certain (intended to be) internal utilities. If you are depending on some of the lesser known exports from apollo-cache
, apollo-cache-inmemory
, or apollo-utilities
, they may no longer be available from @apollo/client
.
@hwillson in #5437 and #5514
Utilities that were previously externally available through the apollo-utilities
package are now only available by importing from @apollo/client/utilities
.
> @hwillson in #5683
Make sure all graphql-tag
public exports are re-exported.
@hwillson in #5861
Fully removed prettier
. The Apollo Client team has decided to no longer automatically enforce code formatting across the codebase. In most cases existing code styles should be followed as much as possible, but this is not a hard and fast rule.
@hwillson in #5227
Make sure ApolloContext
plays nicely with IE11 when storing the shared context.
@ms in #5840
Migrated React Apollo HOC and Components functionality into Apollo Client, making it accessible from @apollo/client/react/components
and @apollo/client/react/hoc
entry points.
@hwillson in #6558
Support passing a context
object through the link execution chain when using subscriptions.
@sgtpepper43 in #4925
MockSubscriptionLink
now supports multiple subscriptions.
@dfrankland in #6081
If you can be sure your application code does not modify cache result objects (see freezeResults
note below), you can unlock substantial performance improvements by communicating this assumption via
new ApolloClient({ assumeImmutableResults: true });
which allows the client to avoid taking defensive snapshots of past results using cloneDeep
, as explained by @benjamn in #4543.
Identical overlapping queries are now deduplicated internally by apollo-client
, rather than using the apollo-link-dedup
package.
@benjamn in commit 7cd8479f
The FetchPolicy
type has been split into two types, so that passing cache-and-network
to ApolloClient#query
is now forbidden at the type level, whereas previously it was forbidden by a runtime invariant
assertion:
export type FetchPolicy =
| "cache-first"
| "network-only"
| "cache-only"
| "no-cache"
| "standby";
export type WatchQueryFetchPolicy = FetchPolicy | "cache-and-network";
The exception thrown if you ignore the type error has also been improved to explain the motivation behind this restriction.
Issue #3130 (comment) and commit cf069bc7
Avoid updating (and later invalidating) cache watches when fetchPolicy
is 'no-cache'
.
@bradleyayers in PR #4573, part of issue #3452
Remove temporary queryId
after fetchMore
completes.
@doomsower in #4440
Call clearStore
callbacks after clearing store.
@ds8k in #4695
Perform all DocumentNode
transforms once, and cache the results.
@benjamn in #4601
Accommodate @client @export
variable changes in ObservableQuery
.
@hwillson in #4604
Support the returnPartialData
option for watched queries again.
@benjamn in #4743
Preserve networkStatus
for incomplete cache-and-network
queries.
@benjamn in #4765
Preserve cache-and-network
fetchPolicy
when refetching.
@benjamn in #4840
Update the React Native docs to remove the request for external example apps that we can link to. We're no longer going to manage a list of external example apps.
@hwillson in #4531
Polling queries are no longer batched together, so their scheduling should be more predictable.
@benjamn in #4800