-
Notifications
You must be signed in to change notification settings - Fork 27k
feat(core): introduce afterRenderEffect
#57549
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
Conversation
|
Deployed adev-preview for 59e169c to: https://ng-dev-previews-fw--pr-angular-angular-57549-adev-prev-oyzoua3t.web.app Note: As new commits are pushed to this pull request, this link is updated after the preview is rebuilt. |
|
I love this change, but since the signalification of the primitive values returned by each phase callback is abstracted away from us, this seems to be a bad fit for use cases that require multiple values to be passed from one phase to another. For example: afterRenderEffect({
earlyRead: () => {
const element = this.someElementRef.nativeElement;
return [element.offsetLeft, element.offsetTop];
},
write: ([x, y]) => animateThing(x, y)
})In this example, I assume that the write phase would run on every render because the earlyRead phase returns a new array each time. Is that correct? The workaround I use today isn't very ergonomic: position = signal<[number,number]>([0,0], {equal: arrayDeepEqual});
afterRender({
earlyRead: () => {
const element = this.someElementRef().nativeElement;
this.position.set([element.offsetLeft, element.offsetTop]);
}
});
// only run the write phase when this.position changes, after accounting for custom equality fn
effect(() => {
const [x, y] = this.position();
afterNextRender({ write: () => animateThing(x, y) });
});It seems to work, but it feels brittle. What do you think? |
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.
Does this mean that if one cleanup function errors, the others don't run but are still cleared?
Should this be more like
for ... {
try {
cleanupFn();
} finally {
this.cleanup?.delete(cleanupFn);
}
}
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.
I thought about this before, and chose (for no strong reason other than intuition) to implement a mental model where we considered all the registered cleanup functions to be a part of the same logical operation. We really need to standardize this model (effect() for example overwrites the previous cleanup function when a new one is registered).
|
LGTM overall but adding a cleanup label since:
|
4c72cab to
4f34cef
Compare
Yeah, we saw this too, but I don't know if there is an API that's ideal here. There seem to be two potential design avenues which address the problem:
Both of these solutions have their downsides. With equality functions, you have to remember to pass them. With more granular return objects, the signal wrapping only works at one layer - if I get creative and |
4f34cef to
4eee890
Compare
Implement the `afterRenderEffect` primitive, which creates effect(s) that run as part of Angular's `afterRender` sequence. `afterRenderEffect` is a useful primitive for expressing DOM operations in a declarative, reactive way. The API itself mirrors `afterRender` and `afterNextRender` with one big difference: values are propagated from phase to phase as signals instead of as plain values. As a result, later phases may not need to execute if the values returned by earlier phases do not change.
4eee890 to
59e169c
Compare
|
@alxhub the |
thePunderWoman
left a comment
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.
reviewed-for: public-api
AndrewKushnir
left a comment
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.
Reviewed-for: public-api
AndrewKushnir
left a comment
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.
Reviewed-for: size-tracking
|
This PR was merged into the repository by commit be2e496. The changes were merged into the following branches: main |
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Implement the
afterRenderEffectprimitive, which creates effect(s) that run as part of Angular'safterRendersequence.afterRenderEffectis a useful primitive for expressing DOM operations in a declarative, reactive way.The API itself mirrors
afterRenderandafterNextRenderwith one big difference: values are propagated from phase to phase as signals instead of as plain values. As a result, later phases may not need to execute if the values returned by earlier phases do not change.