Apollo Client 4.1 is here with significant updates to incremental delivery, fragment watching capabilities, and cache improvements. This release introduces full @stream directive support, compatibility with the latest GraphQL incremental delivery spec, and powerful new APIs for working with fragments.
@stream directive support
Apollo Client 4.1 introduces support for the @stream directive, allowing you to stream array items incrementally from your GraphQL server. @stream works with both the Defer20220824Handler and the newer GraphQL17Alpha9Handler.
The @stream directive is useful when fetching large lists where you want to display items as they become available rather than waiting for the entire response. As each item arrives, Apollo Client updates the cache and notifies your components.
const QUERY = gql`
query FeedQuery {
feed @stream(initialCount: 5) {
id
contents
}
}
`Note: The implementations of @stream differ between GraphQL spec versions in how incremental results are delivered. If you’re upgrading handlers, expect the timing of some incremental results to change.
GraphQL17Alpha9Handler
For servers that use the newer incremental delivery format implemented in graphql@17.0.0-alpha.9, Apollo Client now provides a dedicated handler:
import { GraphQL17Alpha9Handler } from "@apollo/client/incremental";
const client = new ApolloClient({
// ...
incrementalHandler: new GraphQL17Alpha9Handler(),
});This handler supports both @defer and @stream with the updated wire format. The handler automatically sets the appropriate accept header (multipart/mixed;incrementalSpec=v0.2) to request the newest format.
Note: Your GraphQL server must implement the newer incremental delivery format for this handler to work correctly.
Array support for useFragment
You can now pass an array to the from option in useFragment, useSuspenseFragment, and client.watchFragment to watch multiple cache entities simultaneously:
import type { FragmentType } from "@apollo/client";
interface ItemListProps {
items: Array<FragmentType<ItemFragment>>;
}
function ItemList({ items }: ItemListProps) {
const result = useFragment({
fragment: ITEM_FRAGMENT,
from: items,
});
console.log(result);
// {
// data: [{...}, {...}, {...}, ...],
// dataState: "complete",
// complete: true
// }
}This eliminates the need to either hoist the item fragment into the parent fragment or create a child component with useFragment for each array item.
Other notable changes
Bug fixes
- Fixed an issue where incremental payloads returning arrays with fewer items than cached items would incorrectly retain old items (#12923)
fetchMorenow rerenders incremental results when using@deferor@stream(#12925)- Ensured
PreloadedQueryRefinstances are unsubscribed when garbage collected (#12884)
Performance improvements
- Watches and observables created by
useFragment,client.watchFragment, andcache.watchFragmentare now deduplicated for the same object, fragment, and variables. This should improve performance dramatically in cases where the same object is watched in the cache multiple times in the application. (#12927, #13026, #13053)
Other improvements
- The observable returned from
client.watchFragmentnow includes agetCurrentResultfunction to get the current value of the fragment @clientfields with read functions now receiveundefinedfor the cache value instead ofnullwhen a resolver is not defined (#12927)- Support for callback functions as the context option on mutate (#12927)
- Support the
headerstransport for enhanced client awareness (#13043) InMemoryCacheno longer filters out explicitly returnedundefineditems fromreadfunctions for array fields (#13056)prerenderStaticnow exposes the return value to enable the use ofresumeAndPrerenderwith React 19.2 (#13071)- Add support for the
fromoption used withuseFragmenttoclient.readFragment,cache.readFragment,client.writeFragment,cache.writeFragment, andcache.updateFragment. (#13038) - Cache
mergefunctions now receiveextensionsreturned in the response (#13058)
For a full list of changes, please see the 4.1 release notes.
Happy querying!
