-
Notifications
You must be signed in to change notification settings - Fork 2
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
Avoid capturing ComponentDef in a closure for a long time #83
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.
LGTM — nice find 👍
|
||
- Fixed a bug that allowed `ComponentDef` to be captured in closures for a long | ||
time, which could lead to using stale values in complex scenarios where | ||
`ComponentDef` is not constant, but depends on arguments. See [#83](https://github.com/collegevine/purescript-elmish/pull/83). |
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.
Nit: Within the same repo, this syntax will autolink AFAIK 👍
`ComponentDef` is not constant, but depends on arguments. See [#83](https://github.com/collegevine/purescript-elmish/pull/83). | |
`ComponentDef` is not constant, but depends on arguments. See #83. |
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.
No, it doesn't. I tried this first.
@@ -61,6 +63,35 @@ spec = describe "Elmish.Component.wrapWithLocalState" do | |||
findAll ".t--counter" <#> length >>= shouldEqual 2 | |||
findAll ".t--counter" >>= forEach (nearestEnclosingReactComponentName >>= shouldEqual "Elmish_Counter") | |||
|
|||
it "calls the correct closure of `update` when dispatching events" $ |
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.
👍🏻
The
ComponentDef
is captured in closures defined underwhere
inbindComponent
. In most cases this is fine, becauseComponentDef
is constant anyway. And even if not,bindComponent
is called on every render, which means a new, fresh value ofComponentDef
is re-captured on every render.But what if such closure could survive several renders and several changes of
ComponentDef
? If the closure is adispatch
function, the next message that is issued through it will call a stale version ofupdate
. This is particularly important now that we added subscriptions, which keep the initial value ofdispatch
pretty much indefinitely.See the new test I added in this PR to see how this could happen. If the changes to
bindComponent
are undone, that test fails in exactly the way the comment in it predicts.To fix this, I am now keeping
ComponentDef
as a prop on the component, and always retrieving it from the component props when needed, rather than capturing it in a closure. This way, whenever theComponentDef
is required, it is always the one from the latest render.There will be another fix in
purescript-hooks
to take advantage of this fix to fix the next level of the same problem.