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

fix(react): Prevent the operation queue from being flushed during synchronous cache reads #2556

Merged
merged 4 commits into from
Jul 22, 2022

Conversation

kitten
Copy link
Member

@kitten kitten commented Jul 22, 2022

Resolve #2554

⚠️ We urgently recommend all users of the React bindings to upgrade to this patch as soon as it becomes available!
Don't forget to deduplicate @urql/core to the newest version if you do upgrade, since its fix is important.

During some circumstances we may receive an update that then leads to a mount. React may decide to then recursively & synchronously continue this mount. During it, we used to then block other updates using a currentInit flag while the component synchronously reads from the cache. However, since the cache read dispatched its operation (and then terminated), we previously then "piggybacked" off of this dispatch, and flushed other operations.
This means that some potential updates could get lost if they were queued up by the update that lead to the mounted component. We instead want to prevent the queue from further being flushed when the synchronous read terminates, and always schedule a microtick that then gets another chance to flush out the queue.
We furthermore prevent recursive calls from restarting our operation queue.

This allows us to remove the currentInit check entirely and prevent edge cases from causing missed updates. Such cases would always follow this pattern:

  1. The cache updates, e.g. by receiving a new response
  2. The cache schedules multiple component updates
  3. The component updates and mounts a new query
  4. The mounted query prevents further updates
  5. The further updates are processed but cannot update states

The new pattern is now:

  1. The cache updates, e.g. by receiving a new response
  2. The cache schedules multiple component updates
  3. The component updates and mounts a new query
  4. The scheduled updates complete in the next micro-tick

Differentiate between synchronous operation queue runs and
scheduled/deferred queue runs by:
- Using nextOperation directly for non-queue runs
- Interrupting the queue when the source terminates
- Always scheduling a deferred queue flush even if it'll have nothing to flush
@kitten kitten requested a review from JoviDeCroock July 22, 2022 15:04
@changeset-bot
Copy link

changeset-bot bot commented Jul 22, 2022

🦋 Changeset detected

Latest commit: 5c0269d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@urql/core Patch
urql Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@kitten kitten force-pushed the fix/sync-eager-operation-queue branch from 67dbf79 to 5c0269d Compare July 22, 2022 15:05
@kitten kitten merged commit 3217333 into main Jul 22, 2022
@kitten kitten deleted the fix/sync-eager-operation-queue branch July 22, 2022 15:12
@urql-ci urql-ci mentioned this pull request Jul 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

useQuery not being re-rendered after manual cache update
2 participants