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

Make updating cache.makeVar variables broadcast watches. #5976

Merged
merged 3 commits into from
Feb 21, 2020

Conversation

benjamn
Copy link
Member

@benjamn benjamn commented Feb 21, 2020

This PR makes two user-visible changes:

  • The cache.makeLocalVar API introduced in Implement reactive variables for tracking local state. #5799 has been renamed to cache.makeVar, for brevity and to avoid direct association with Apollo Client 2.x local state. Reactive variables should replace most use cases for local state, but they have many other potential uses. The type of the returned variable is now ReactiveVar<T> instead of LocalVar<T>.
  • Updating a reactive variable with a new value will now trigger a call to cache.broadcastWatches(). Because the ApolloCache API is mostly synchronous, this broadcast is also synchronous, but it's possible to batch multiple variable updates together by performing them within a cache.performTransaction block.

These changes are vital for making reactive variables truly reactive, but we still have some work to do to make sure broadcasting watched query data from the cache reliably pushes the new data into the view layer.

This essentially undoes #5484, so that reactive variables (which have
access to the InMemoryCache object but know nothing about proxy objects)
can benefit from transactional broadcast batching when calling
cache.broadcastWatches().
Shorter, and not as suggestive of Apollo Client 2.x local state. Returns a
function of type ReactiveVar<T> (f.k.a. LocalVar<T>).

Follow-up to #5799.
The broadcast is always synchronous, but you can group multiple variable
updates together (with just one broadcast) using cache.performTransaction.
@benjamn benjamn added this to the Release 3.0 milestone Feb 21, 2020
@benjamn benjamn self-assigned this Feb 21, 2020
Copy link
Member

@hwillson hwillson left a comment

Choose a reason for hiding this comment

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

Looks great @benjamn! 🎉

@benjamn benjamn merged commit 03f00a1 into master Feb 21, 2020
@benjamn benjamn deleted the reactive-cache.makeVar-broadcast branch February 21, 2020 19:59
benjamn added a commit that referenced this pull request Jun 30, 2020
The makeVar method was originally attached to InMemoryCache so that we
could call cache.broadcastWatches() whenever the variable was updated.
See #5799 and #5976 for background.

However, as a number of developers have reported, requiring access to an
InMemoryCache to create a ReactiveVar can be awkward, since the code that
calls makeVar may not be colocated with the code that creates the cache,
and it is often desirable to create and initialize reactive variables
before the cache has been created.

As this commit shows, the ReactiveVar function can infer the current
InMemoryCache from a contextual Slot, when called without arguments (that
is, when reading the variable). When the variable is updated (by passing a
new value to the ReactiveVar function), any caches that previously read
the variable will be notified of the update. Since this logic happens at
variable access time rather than variable creation time, makeVar can be a
free-floating global function, importable directly from @apollo/client.

This new system allows the variable to become associated with any number
of InMemoryCache instances, whereas previously a given variable was only
ever associated with one InMemoryCache. Note: when I say "any number" I
very much mean to include zero, since a ReactiveVar that has not been
associated with any caches yet can still be used as a container, and will
not trigger any broadcasts when updated.

The Slot class that makes this all work may seem like magic, but we have
been using it ever since Apollo Client 2.5 (#3394, via the optimism
library), so it has been amply battle-tested. This magic works.
@benjamn
Copy link
Member Author

benjamn commented Jun 30, 2020

Just a quick note that we've made this API even easier to use (makeVar is just a free-floating function now): #6512

benjamn added a commit that referenced this pull request Jun 30, 2020
…6512)

The makeVar method was originally attached to InMemoryCache so that we
could call cache.broadcastWatches() whenever the variable was updated.
See #5799 and #5976 for background.

However, as a number of developers have reported, requiring access to an
InMemoryCache to create a ReactiveVar can be awkward, since the code that
calls makeVar may not be colocated with the code that creates the cache,
and it is often desirable to create and initialize reactive variables
before the cache has been created.

As this commit shows, the ReactiveVar function can infer the current
InMemoryCache from a contextual Slot, when called without arguments (that
is, when reading the variable). When the variable is updated (by passing a
new value to the ReactiveVar function), any caches that previously read
the variable will be notified of the update. Since this logic happens at
variable access time rather than variable creation time, makeVar can be a
free-floating global function, importable directly from @apollo/client.

This new system allows the variable to become associated with any number
of InMemoryCache instances, whereas previously a given variable was only
ever associated with one InMemoryCache. Note: when I say "any number" I
very much mean to include zero, since a ReactiveVar that has not been
associated with any caches yet can still be used as a container, and will
not trigger any broadcasts when updated.

The Slot class that makes this all work may seem like magic, but we have
been using it ever since Apollo Client 2.5 (#3394, via the optimism
library), so it has been amply battle-tested. This magic works.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants