Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve standalone client.refetchQueries method to support automatic detection of queries needing to be refetched. #8000

Merged
merged 47 commits into from May 18, 2021

Conversation

benjamn
Copy link
Member

@benjamn benjamn commented Apr 16, 2021

As promised in #7878 (comment) and #7827 (comment), this PR turns the client.refetchQueries method into a one-stop solution for refetching queries (without having to perform a mutation), tying together several previous ways of triggering refetches into a single, flexible API.

This is the last major piece of new functionality that we plan to add to Apollo Client v3.4, and is intended to complement similar functionality added to mutations (options.onQueryUpdated, previously called options.reobserveQuery) in #7827, and builds on the cache.batch primitive added to InMemoryCache in #7819. If this PR is merged, it should conclude the implementation of the following item from the Apollo Client v3.4 ROADMAP.md section:

  • A new API for reobserving/refetching queries after a mutation, eliminating the need for updateQueries, refetchQueries, and awaitRefetchQueries in a lot of cases.

Since the API has changed since I last sketched it out, here's an overview of the current functionality:

const { queries, results } = client.refetchQueries({
  updateCache(cache) {
    // Trigger query updates by updating the client.cache in any way you like.
    // To pick just one possible example:
    cache.evict({
      id: cache.identify(...),
      fieldName,
    });
  },

  // Make sure these queries are included even if they were not affected by the
  // updateCache function (or the updateCache function was not provided). This
  // option is similar to the existing refetchQueries option for mutations.
  include: ["QueryName", "AnotherQueryName"],

  // Optional callback that will be called for every ObservableQuery that was affected
  // by updateCache (or included explicitly by name). If onQueryUpdated is not
  // provided, the affected queries will be refetched by calling obsQuery.refetch().
  onQueryUpdated(obsQuery, diff) {
    if (shouldIgnoreUpdate(obsQuery, diff)) {
      // Returning false causes this query not to be refetched, and omits its result from
      // the client.refetchQueries(...).{queries,updates} arrays.
      return false;
    }
    // Providing an onQueryUpdated function allows dynamically determining whether/how
    // each query should be refetched. Anything you return here will end up in the
    // client.refetchQueries(...).updates array.
    return obsQuery.refetch();
  },

  // Passing optimistic: false (the default) causes the updateCache function to run
  // against the root (non-optimistic) cache layer. Passing optimistic: true causes
  // updateCache to run in a temporary optimistic cache layer that client.refetchQueries
  // removes before returning, which can be useful when you want to use updateCache
  // to trigger some refetches but you don't want to modify cache data permanently.
  optimistic: true,
});

All of these options (updateCache, include, onQueryUpdated, and optimistic) are optional, but you have to pass either updateCache or include to get any queries to be refetched by client.refetchQueries.

This PR is a work-in-progress because this still needs more tests and documentation, but I wanted to share my progress so far, so folks can share their thoughts on this new client.refetchQueries API.

@benjamn benjamn added this to the Release 3.4 milestone Apr 16, 2021
@benjamn benjamn self-assigned this Apr 16, 2021
@benjamn benjamn marked this pull request as draft April 16, 2021 21:07
@benjamn benjamn changed the title Client.refetch queries revamp Improve standalone client.refetchQueries method to support automatic detection of queries needing to be refetched. Apr 16, 2021
@benjamn benjamn added this to In progress in Release 3.4 Apr 16, 2021
src/core/ApolloClient.ts Outdated Show resolved Hide resolved
src/core/QueryManager.ts Outdated Show resolved Hide resolved
Comment on lines +367 to +406
if (typeof removeOptimistic === "string") {
this.optimisticData = this.optimisticData.removeLayer(removeOptimistic);
}
Copy link
Member Author

@benjamn benjamn Apr 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removeOptimistic option is a powerful but easy-to-miss new feature of cache.batch, since it allows us to remove optimistic mutation layers at the same time (within the same batch operation) as the final mutation update, triggering only one broadcastWatches call for both the removal and the update. Previously, optimistic layers were removed separately, after the final update, which could trigger more than one broadcast (likely harmless but potentially noisy).

src/core/QueryManager.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@brainkim brainkim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely more review tomorrow but I’m punching out for the day.

src/__tests__/client.ts Outdated Show resolved Hide resolved
src/cache/inmemory/inMemoryCache.ts Outdated Show resolved Hide resolved
src/cache/core/cache.ts Outdated Show resolved Hide resolved
src/cache/core/types/Cache.ts Show resolved Hide resolved
src/cache/inmemory/inMemoryCache.ts Show resolved Hide resolved
src/core/types.ts Outdated Show resolved Hide resolved
src/core/__tests__/QueryManager/index.ts Show resolved Hide resolved
src/core/watchQueryOptions.ts Outdated Show resolved Hide resolved
src/core/QueryManager.ts Show resolved Hide resolved
@benjamn benjamn force-pushed the client.refetchQueries-revamp branch from 20d6c78 to 526869f Compare April 20, 2021 15:03
benjamn added a commit that referenced this pull request Apr 20, 2021
@benjamn benjamn force-pushed the client.refetchQueries-revamp branch from 26639f0 to 19d357f Compare April 20, 2021 21:36
benjamn added 17 commits May 18, 2021 16:39
Previously, removing an optimistic EntityStore layer with
removeOptimistic would dirty all fields of any StoreObjects contained by
the removed layer, ignoring the possibility that some of those field
values might have been inherited as-is from the parent layer.

With this commit, we dirty only those fields whose values will be
observably changed by removing the layer, which requires comparing field
values between the layer-to-be-removed and its parent layer.
Notice that the type of `results` in

  client.refetchQueries(...).then(results => ...)

is correctly inferred to be ApolloQueryResult<any>[], because the
onQueryUpdated function returned true, which triggers a refetch, which
returns a Promise<ApolloQueryResult<any>>.
@benjamn benjamn force-pushed the client.refetchQueries-revamp branch from 318039c to 512804c Compare May 18, 2021 20:41
@benjamn
Copy link
Member Author

benjamn commented May 18, 2021

@brainkim @timbotnik @hwillson I added support for including queries by DocumentNode (rather than just by name) in commit 512804c:

client.refetchQueries({
  include: [queryObject],
  onQueryUpdated(obs, diff) {
    return obs.refetch();
  },
})

I'd like to merge this PR soon so I can start working on the docs (which aren't rendering on this branch), so let me know soonish if you have any additional feedback here. Thanks!

@benjamn benjamn merged commit a5c3308 into release-3.4 May 18, 2021
@benjamn benjamn deleted the client.refetchQueries-revamp branch May 18, 2021 20:50
Copy link
Contributor

@brainkim brainkim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm 🎉

@hwillson hwillson moved this from In progress to Done in Release 3.4 May 25, 2021
@hwillson hwillson removed this from the MM-2021-06 milestone Jul 29, 2021
@apollographql apollographql locked as resolved and limited conversation to collaborators Feb 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

5 participants