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

Recheck reactive variable's value in commit phase #7652

Merged
merged 2 commits into from
Feb 4, 2021

Conversation

jcreighton
Copy link
Contributor

@jcreighton jcreighton commented Feb 4, 2021

Fixes #7609. Because #7581 amended useReactiveVar to set the onNextChange handler in a useEffect, an end user could see inconsistent data if updating a reactive var in a useEffect higher in the component tree. That change wouldn't be caught lower in the tree as onNextChange wouldn't be set yet. (useEffect is called during the commit phase and also in order from top to bottom.) This PR adds an additional check for a change in the value, scheduling an update if the value has changed.

Checklist:

  • If this PR is a new feature, please reference an issue where a consensus about the design was reached (not necessary for small changes)
  • Make sure all of the significant new logic is covered by tests

@jcreighton jcreighton requested a review from benjamn February 4, 2021 18:07
@jcreighton jcreighton force-pushed the 7609-useReactiveVar-regression branch from 8e34eaa to 1d216a3 Compare February 4, 2021 19:59
Copy link
Member

@benjamn benjamn left a comment

Choose a reason for hiding this comment

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

Makes sense to me (after our discussion). Thanks @jcreighton!

@jcreighton jcreighton merged commit 541d333 into main Feb 4, 2021
@jcreighton jcreighton deleted the 7609-useReactiveVar-regression branch February 4, 2021 22:31
benjamn added a commit that referenced this pull request May 4, 2021
While rereading the code @jcreighton added in #7652, I remembered it's
safe to call rv() in a useEffect callback (without useReactiveVar),
which allows us to compare the latest variable value to the previous
value before deciding whether to call rv.onNextChange(setValue) in the
effect callback function. If the values already disagree, we can skip
listening and just call setValue right away.

In React <StrictMode>, the two initial rv() values generated prior to
the useIsomorphicEffect callback should always be the same, unless the
reactive variable somehow gets updated in between those renders, which I
don't think is possible, since React invokes those renders sychronously,
one after the other:
https://github.com/facebook/react/blob/0e100ed00fb52cfd107db1d1081ef18fe4b9167f/packages/react-reconciler/src/ReactUpdateQueue.new.js#L391-L399

The key difference between this approach and calling rv.onNextChange
synchronously in render is that (in this new approach) we can ignore the
extra value without doing anything to clean up its resources, whereas
with rv.onNextChange we were also responsible for calling the extra
cancel function produced by the extra rv.onNextChange call.
@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.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update in reactive vars do NOT cause expected re-renders in 3.3.7 (regression)
2 participants