-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Conversation
There was a problem hiding this 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!
Just to add - we'll want to get some docs for this in place as well. |
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])}> |
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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?
There was a problem hiding this 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[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const items = [...set]
?
There was a problem hiding this comment.
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.
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 usinguseQuery
(or GraphQL at all) to benefit from the reactivity thatReactiveVar<T>
provides.Implementing
useReactiveVar
required generalizing theReactiveVar<T>
API to allow arbitrary listeners (not justInMemoryCache
objects),but fortunately the existing cache broadcast logic fits nicely within the new listener API(this unification was reverted after discussion with @glasser below).