This repository has been archived by the owner on Feb 24, 2020. It is now read-only.
[WIP] BUG: 'Long-lived' setState function fails to persist updates #44
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Issue: It seems that there is a 'state persistence' issue - state updated higher in the hierarchy can pave state lower in the hierarchy, when state lower in the hierarchy is set via a 'long-lived' setState handler. I hit this issue when I was working on the
slider
prototype control in Revery.It was a little tricky to reproduce in isolation, but I believe there are a couple of conditions required to hit this bug:
setState
type function acquired fromuseState
. This could take a couple forms - auseEffect
that setscondition=Effects.MountUnmount
(so it is only fired in the initial mount), or an event handler like in theMouse.setCapture
case. The initialmousedown
successfully triggers a state update, but subsequent state updates called during themousemove
events are ignored.revery
, this happens due to the UI update that occurs in therender
function, or when an ancestor component calls a function in response to an event from a lower component (ie, a component listening toonValueChanged
from a slider).I created a test case so far in the PR to 'exercise' this case - I believe if we can get the test case fixed, it'll also address the bugs I saw with the slider functionality. The new test runs the following in sequence:
We'd expect at the end that the inner component would have state 6, but it actually reverts back to its original value of 2 after the last outer component update.
Defect: My understanding so far is that, when code 'hangs on' to a
setState
function provided byuseState
, in the scenario outlined above - what happens is that when the handler down the road calls the oldsetState
, it will update a detached instance that isn't up-to-date.Potential Fixes: I think the crux of the issue is here:
In that the
currentContext
is out-of-date in this particular case.There is some awkwardness in how we manage the state today:
(this concept is overloaded - we use the
context
to store the entire component instance, and then there are these separate fields looking at currentState/newState - it makes it hard to understand the chain of operations here).I'm considering a refactor where we give each instance a unique instance ID. Then, instead of currying the entire context to
dispatch
, we could dispatch this ID, which should persist across re-renders as long as the instance is still available. Then, the state management becomes a hash table ofuniqueId
->instance
, and managing our hierarchy of instances means managing a tree ofuniqueId
. I believe this could simplify the state management of instances while addressing the bug exposed by the test case - thesetState
could never refer to an old node unless it had been removed from the tree (in which case we could detect it and log a warning).