-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
[BUGFIX][FEAT][Tracked Properties] Adds Arg Proxy Feature Flag #17835
Conversation
6de8129
to
e4d7460
Compare
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.
Seems good to me, and given that its behind a feature flag it should be easy to roll back if we end up wanting to.
👍
packages/@ember/-internals/glimmer/lib/component-managers/custom.ts
Outdated
Show resolved
Hide resolved
3a8c092
to
d5579ca
Compare
I believe this may fix a problem I've experienced porting ember-basic-drodown to glimmer. I have a CP that depends on
Copying explanation from @pzuraq:
In case this help creating a test that validates the fix |
What's the state of this? I can help verify that it fixes my issue upgrading my addons |
@cibernox there will likely need to be a little additional work for it to fix your issue, we're working on a followup to the Tracked Properties RFC that will address some core issues we've found with interop between computed properties and tracked properties at the moment. This is semi-related, but on its own it likely won't fix your issue just yet. |
I can try to add a failing test for my issue if that helps, I think I've isolated it. Idk if it should be in ember or in glimmer |
d5579ca
to
71ac2ec
Compare
if (DEBUG) { | ||
handler.set = function(target, prop) { | ||
assert( | ||
`You attempted to set ${target}#${String( |
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.
We chatted a bit about this, but I'd like to get the component itself into this message target
is going to be the empty {}
POJO you make just above. Can we update this to definition.ComponentClass.class
instead? At least it would toString the component name...
71ac2ec
to
88ac5c1
Compare
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, lets land once CI is green...
Currently, we pass a captured snapshot of arguments to the custom component manager and expect users to update their `args` and trigger notifications, dirtying any getters that rely on `args`. This is problematic for a few reasons: 1. It's fundamentally less efficient, since every getter on a component will invalidate any time _any_ of the arguments on the component changes. This may not be a huge deal in most components, but it could be problematic at scale. 2. Upstream components will currently rerender if anything changes downstream of them. The second problem is more of an issue here. The crux of the issue is that as we are rendering, we must somehow dirty the `args` object in order for getters to invalidate. Currently, there are two ways of doing this: 1. Dirtying the tag and bumping the global revision count. This results in the component itself being dirtied, which causes arguments to be assigned again on the next render, which dirties everything again. 2. Setting the argument's tag to `CURRENT_TAG`, as we do in Glimmer.js. This always returns the _latest_ revision though, which means that we are _always_ dirty. This issue can crop up in many forms and leads to infinite rerender bugs when it does. The solution proposed here is to instead use a Proxy (or an object with manually defined getters on platforms which do not support Proxy) to wrap `args`. This allows us to directly access the references that represent the arguments, and push their tags onto the autotrack stack as accessed. Everything entangles properly, and we only rerender or recalculate a getter when needed. Alternatively, we could add a way to set the `args` tag to _exactly_ the current revision as the component is rendering. This would solve the problems of upstream invalidations, but would not solve the issue of all getters on a component invalidating each render.
88ac5c1
to
af9ddaf
Compare
I'm running in to this issue .... at first i thought i had to do |
Currently, we pass a captured snapshot of arguments to the custom
component manager and expect users to update their
args
and triggernotifications, dirtying any getters that rely on
args
. This isproblematic for a few reasons:
will invalidate any time any of the arguments on the component
changes. This may not be a huge deal in most components, but it could
be problematic at scale.
downstream of them.
The second problem is more of an issue here. The crux of the issue is
that as we are rendering, we must somehow dirty the
args
object inorder for getters to invalidate. Currently, there are two ways of doing
this:
in the component itself being dirtied, which causes arguments to be
assigned again on the next render, which dirties everything again.
CURRENT_TAG
, as we do in Glimmer.js.This always returns the latest revision though, which means that we
are always dirty.
This issue can crop up in many forms and leads to infinite rerender bugs
when it does.
The solution proposed here is to instead use a Proxy (or an object with
manually defined getters on platforms which do not support Proxy) to
wrap
args
. This allows us to directly access the references thatrepresent the arguments, and push their tags onto the autotrack stack as
accessed. Everything entangles properly, and we only rerender or
recalculate a getter when needed.
Alternatively, we could add a way to set the
args
tag to exactlythe current revision as the component is rendering. This would solve the
problems of upstream invalidations, but would not solve the issue of all
getters on a component invalidating each render.
Fixes #17799