@apollo/client
Advanced tools
Changelog
3.9.3
#11525 dce923a
Thanks @vezaynk! - Allows passing in client via options to useFragment
#11558 8cba16f
Thanks @alessbell! - Fix unbound-method
linter error on ObservableQuery methods exposed on useQuery's QueryResult object.
Changelog
3.9.2
6ac2b0c
Thanks @jerelmiller! - Fix import in useLazyRef
causing import issues in the nextjs package.Changelog
3.9.1
#11516 8390fea
Thanks @phryneas! - Fix an incorrect string substitution in a warning message.
#11515 c9bf93b
Thanks @vladar! - Avoid redundant refetchQueries call for mutation with no-cache policy (fixes #10238)
#11545 84a6bea
Thanks @alessbell! - Remove error thrown by inFlightLinkObservables
intended to be removed before 3.9 release.
Changelog
3.9.0
#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
WeakCache
instead of Map
to keep a limited number of parsed resultsparse.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
WeakCache
instead of WeakMap
to keep a limited number of hash resultspersistedLink.resetHashCache()
method#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
useLoadableQuery
#11300 a815873
Thanks @jerelmiller! - Introduces a new useLoadableQuery
hook. This hook works similarly to useBackgroundQuery
in that it returns a queryRef
that can be used to suspend a component via the useReadQuery
hook. It provides a more ergonomic way to load the query during a user interaction (for example when wanting to preload some data) that would otherwise be clunky with useBackgroundQuery
.
function App() {
const [loadQuery, queryRef, { refetch, fetchMore, reset }] =
useLoadableQuery(query, options);
return (
<>
<button onClick={() => loadQuery(variables)}>Load query</button>
<Suspense fallback={<SuspenseFallback />}>
{queryRef && <Child queryRef={queryRef} />}
</Suspense>
</>
);
}
function Child({ queryRef }) {
const { data } = useReadQuery(queryRef);
// ...
}
createQueryPreloader
#11412 58db5c3
Thanks @jerelmiller! - Add the ability to start preloading a query outside React to begin fetching as early as possible. Call createQueryPreloader
to create a preloadQuery
function which can be called to start fetching a query. This returns a queryRef
which is passed to useReadQuery
and suspended until the query is done fetching.
const preloadQuery = createQueryPreloader(client);
const queryRef = preloadQuery(QUERY, { variables, ...otherOptions });
function App() {
return {
<Suspense fallback={<div>Loading</div>}>
<MyQuery />
</Suspense>
}
}
function MyQuery() {
const { data } = useReadQuery(queryRef);
// do something with data
}
#11178 4d64a6f
Thanks @sebakerckhof! - Support re-using of mocks in the MockedProvider
#6701 8d2b4e1
Thanks @prowe! - Ability to dynamically match mocks
Adds support for a new property MockedResponse.variableMatcher
: a predicate function that accepts a variables
param. If true
, the variables
will be passed into the ResultFunction
to help dynamically build a response.
useQueryRefHandlers
hook#11412 58db5c3
Thanks @jerelmiller! - Create a new useQueryRefHandlers
hook that returns refetch
and fetchMore
functions for a given queryRef
. This is useful to get access to handlers for a queryRef
that was created by createQueryPreloader
or when the handlers for a queryRef
produced by a different component are inaccessible.
const MyComponent({ queryRef }) {
const { refetch, fetchMore } = useQueryRefHandlers(queryRef);
// ...
}
optimisticResponse
updates with the IGNORE
sentinel object#11410 07fcf6a
Thanks @sf-twingate! - Allow returning IGNORE
sentinel object from optimisticResponse
functions to bail-out from the optimistic update.
Consider this example:
const UPDATE_COMMENT = gql`
mutation UpdateComment($commentId: ID!, $commentContent: String!) {
updateComment(commentId: $commentId, content: $commentContent) {
id
__typename
content
}
}
`;
function CommentPageWithData() {
const [mutate] = useMutation(UPDATE_COMMENT);
return (
<Comment
updateComment={({ commentId, commentContent }) =>
mutate({
variables: { commentId, commentContent },
optimisticResponse: (vars, { IGNORE }) => {
if (commentContent === "foo") {
// conditionally bail out of optimistic updates
return IGNORE;
}
return {
updateComment: {
id: commentId,
__typename: "Comment",
content: commentContent,
},
};
},
})
}
/>
);
}
The IGNORE
sentinel can be destructured from the second parameter in the callback function signature passed to optimisticResponse
.
#11301 46ab032
Thanks @alessbell! - Add multipart subscription network adapters for Relay and urql
import { createFetchMultipartSubscription } from "@apollo/client/utilities/subscriptions/relay";
import { Environment, Network, RecordSource, Store } from "relay-runtime";
const fetchMultipartSubs = createFetchMultipartSubscription(
"http://localhost:4000"
);
const network = Network.create(fetchQuery, fetchMultipartSubs);
export const RelayEnvironment = new Environment({
network,
store: new Store(new RecordSource()),
});
import { createFetchMultipartSubscription } from "@apollo/client/utilities/subscriptions/urql";
import { Client, fetchExchange, subscriptionExchange } from "@urql/core";
const url = "http://localhost:4000";
const multipartSubscriptionForwarder = createFetchMultipartSubscription(url);
const client = new Client({
url,
exchanges: [
fetchExchange,
subscriptionExchange({
forwardSubscription: multipartSubscriptionForwarder,
}),
],
});
skipPollAttempt
callback function#11397 3f7eecb
Thanks @aditya-kumawat! - Adds a new skipPollAttempt
callback function that's called whenever a refetch attempt occurs while polling. If the function returns true
, the refetch is skipped and not reattempted until the next poll interval. This will solve the frequent use-case of disabling polling when the window is inactive.
useQuery(QUERY, {
pollInterval: 1000,
skipPollAttempt: () => document.hidden, // or !document.hasFocus()
});
// or define it globally
new ApolloClient({
defaultOptions: {
watchQuery: {
skipPollAttempt: () => document.hidden, // or !document.hasFocus()
},
},
});