Skip to content
This repository has been archived by the owner on Apr 3, 2024. It is now read-only.

Unconditionally flushing effects is unsafe #3

Closed
billyjanitsch opened this issue Apr 20, 2020 · 1 comment · Fixed by #5
Closed

Unconditionally flushing effects is unsafe #3

billyjanitsch opened this issue Apr 20, 2020 · 1 comment · Fixed by #5
Labels
bug Something isn't working

Comments

@billyjanitsch
Copy link
Contributor

billyjanitsch commented Apr 20, 2020

Hi! This implementation has a bug that can cause effects to be permanently skipped.

The special flush event clears all pending effects from the queue:

if (event === flushEffectsSymbol) {
// Record that effects have already been executed
return [state, []];
}

This seems fine because event is dispatched after clearing all effects in the queue:

useEffect(() => {
if (stateEffectTuples.length) {
stateEffectTuples.forEach(([stateForEffect, effects]) => {

dispatch(flushEffectsSymbol);

The problem is that this effect closes over stateEffectTuples. It's possible that new effects will be added to the queue in between the render and the execution of the effect. These effects won't be executed in the effect because of the closure, but they will be cleared by the flush event. So they will effectively be skipped.

Here's a sandbox demonstrating the problem. Click "increment" and notice that the state correctly updates to 2, but the console has only printed INC 0. We'd expect it to also print INC 1. The latter effect was skipped because the second increment was added to the queue after the closure but before the dispatch of the flush event. So the effect gets added to the queue and then cleared without having a chance to run.

One potential solution would be to slice off the first stateEffectTuples.length elements from the state at the time of the update rather than unconditionally returning []. Essentially this is saying "flush the effects that were just run" rather than "flush all effects".

@davidkpiano
Copy link
Owner

Can you make a failing test for this issue? Or better yet, a PR?

Otherwise I'll get to this soon.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants