Skip to content

3.4.0

Compare
Choose a tag to compare
@benjamn benjamn released this 28 Jul 17:40
· 2855 commits to main since this release
550ec23

Apollo Client 3.4.0

New documentation

Improvements

  • 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 #8701

  • 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

Potentially disruptive changes

  • 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

Bug fixes

  • 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