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

Implement useReactiveVar hook for consuming reactive variables in React components. #6867

Merged
merged 6 commits into from
Aug 20, 2020

Conversation

benjamn
Copy link
Member

@benjamn benjamn commented Aug 20, 2020

This PR implements a React hook called useReactiveVar (requested in #6818), which can be used to read from a reactive variable in a way that allows the React component to rerender if/when the variable is next updated.

Previously, the only way for a reactive variable to trigger a React component rerender was through the use of useQuery. As the tests included in this PR demonstrate, you don't have to be using useQuery (or GraphQL at all) to benefit from the reactivity that ReactiveVar<T> provides.

Implementing useReactiveVar required generalizing the ReactiveVar<T> API to allow arbitrary listeners (not just InMemoryCache objects), but fortunately the existing cache broadcast logic fits nicely within the new listener API (this unification was reverted after discussion with @glasser below).

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.

This is great @benjamn! 🎉 And I love that the hook body is only 4 lines 😂. Thanks for this!

@hwillson
Copy link
Member

Just to add - we'll want to get some docs for this in place as well.

src/cache/inmemory/reactiveVars.ts Outdated Show resolved Hide resolved
@benjamn benjamn requested a review from StephenBarlow as a code owner August 20, 2020 20:18
A common pitfall when using forEach to iterate over a set of callback
functions, thankfully caught by the tests I wrote.
This restores the cache broadcast behavior prior to #6867, since @glasser
persuaded me it could be risky to handle caches the same way we handle
onNextChange listener functions:
#6867 (comment)

Unification is nice, but avoiding unnecessary breaking changes is nicer.
return (
<div class="add-to-cart-button">
<Button onClick={() => cartItemsVar([...cartItems, productId])}>
<Button onClick={() => cartItemsVar([...cartItemsVar(), productId])}>
Copy link
Member Author

Choose a reason for hiding this comment

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

This was risky because the button could be clicked long after the component was first rendered.

@@ -199,7 +196,32 @@ export function Cart() {
}
```

</ExpansionPanel>
Alternatively, you can read directly from a reactive variable using the `useReactiveVar` hook introduced in Apollo Client 3.2.0:
Copy link
Member Author

Choose a reason for hiding this comment

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

@StephenBarlow Is it okay to refer to an Apollo Client version number in the docs like this?

Copy link
Member

@glasser glasser left a comment

Choose a reason for hiding this comment

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

I didn't review the tests or docs.

// to the original elements of the set before we begin iterating. See
// iterateObserversSafely for another example of this pattern.
function consumeAndIterate<T>(set: Set<T>, callback: (item: T) => any) {
const items: T[] = [];
Copy link
Member

Choose a reason for hiding this comment

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

const items = [...set] ?

Copy link
Member Author

@benjamn benjamn Aug 20, 2020

Choose a reason for hiding this comment

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

You have every reason to expect that to work, but TypeScript complains:

Type 'Set<T>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators. [2569]

The ugly truth is that --downlevelIteration adds overhead to all ...spread operations (even the Array-only ones), so that's unfortunately not an option for us, until we're comfortable dropping support for Internet Explorer.

src/cache/inmemory/reactiveVars.ts Show resolved Hide resolved
@benjamn benjamn merged commit 83e2c1b into release-3.2 Aug 20, 2020
@benjamn benjamn deleted the useReactiveVar branch August 20, 2020 23:50
@benjamn benjamn mentioned this pull request Aug 21, 2020
11 tasks
@jpvajda jpvajda mentioned this pull request Jul 15, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 1, 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.

4 participants