Skip to content

Commit be2e496

Browse files
alxhubAndrewKushnir
authored andcommitted
feat(core): introduce afterRenderEffect (#57549)
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. PR Close #57549
1 parent c2892fe commit be2e496

7 files changed

Lines changed: 741 additions & 3 deletions

File tree

goldens/public-api/core/index.api.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ export function afterRender<E = never, W = never, M = never>(spec: {
4949
// @public
5050
export function afterRender(callback: VoidFunction, options?: AfterRenderOptions): AfterRenderRef;
5151

52+
// @public
53+
export function afterRenderEffect(callback: (onCleanup: EffectCleanupRegisterFn) => void, options?: Omit<AfterRenderOptions, 'phase'>): AfterRenderRef;
54+
55+
// @public
56+
export function afterRenderEffect<E = never, W = never, M = never>(spec: {
57+
earlyRead?: (onCleanup: EffectCleanupRegisterFn) => E;
58+
write?: (...args: [...ɵFirstAvailableSignal<[E]>, EffectCleanupRegisterFn]) => W;
59+
mixedReadWrite?: (...args: [...ɵFirstAvailableSignal<[W, E]>, EffectCleanupRegisterFn]) => M;
60+
read?: (...args: [...ɵFirstAvailableSignal<[M, W, E]>, EffectCleanupRegisterFn]) => void;
61+
}, options?: Omit<AfterRenderOptions, 'phase'>): AfterRenderRef;
62+
5263
// @public
5364
export interface AfterRenderOptions {
5465
injector?: Injector;

goldens/size-tracking/integration-payloads.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
},
88
"cli-hello-world-ivy-i18n": {
99
"uncompressed": {
10-
"main": 130590,
11-
"polyfills": 34676
10+
"main": 135813,
11+
"polyfills": 35883
1212
}
1313
},
1414
"cli-hello-world-lazy": {

packages/core/src/core_reactivity_export_internal.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ export {
2323
EffectCleanupRegisterFn,
2424
EffectScheduler as ɵEffectScheduler,
2525
} from './render3/reactivity/effect';
26+
export {afterRenderEffect, ɵFirstAvailableSignal} from './render3/reactivity/after_render_effect';
2627
export {assertNotInReactiveContext} from './render3/reactivity/asserts';

packages/core/src/render3/after_render/hooks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,6 @@ function afterRenderImpl(
459459
}
460460

461461
/** `AfterRenderRef` that does nothing. */
462-
const NOOP_AFTER_RENDER_REF: AfterRenderRef = {
462+
export const NOOP_AFTER_RENDER_REF: AfterRenderRef = {
463463
destroy() {},
464464
};

0 commit comments

Comments
 (0)