diff --git a/goldens/size-tracking/integration-payloads.json b/goldens/size-tracking/integration-payloads.json index fe8a61ccb84ed1..a1885374cef1ad 100644 --- a/goldens/size-tracking/integration-payloads.json +++ b/goldens/size-tracking/integration-payloads.json @@ -20,7 +20,7 @@ }, "forms": { "uncompressed": { - "main": 176726, + "main": 181773, "polyfills": 33772 } }, diff --git a/packages/core/src/render3/reactivity/effect.ts b/packages/core/src/render3/reactivity/effect.ts index 6317b9fd3e454b..dd8552e0fd0b9a 100644 --- a/packages/core/src/render3/reactivity/effect.ts +++ b/packages/core/src/render3/reactivity/effect.ts @@ -312,6 +312,7 @@ export const ROOT_EFFECT_NODE: Omit { let prev: boolean; @@ -487,6 +484,53 @@ describe('reactivity', () => { (fix.componentInstance.injector as Injector & {destroy(): void}).destroy(); expect(destroyed).toBeTrue(); }); + + it('should not run root effects after it has been destroyed', async () => { + let effectCounter = 0; + const counter = signal(1); + const effectRef = TestBed.runInInjectionContext(() => + effect( + () => { + counter(); + effectCounter++; + }, + {injector: TestBed.inject(EnvironmentInjector)}, + ), + ); + expect(effectCounter).toBe(0); + effectRef.destroy(); + TestBed.flushEffects(); + expect(effectCounter).toBe(0); + + counter.set(2); + TestBed.flushEffects(); + expect(effectCounter).toBe(0); + }); + + it('should not run view effects after it has been destroyed', async () => { + let effectCounter = 0; + + @Component({template: ''}) + class TestCmp { + counter = signal(1); + effectRef = effect(() => { + this.counter(); + effectCounter++; + }); + } + + const fixture = TestBed.createComponent(TestCmp); + fixture.componentInstance.effectRef.destroy(); + fixture.detectChanges(); + expect(effectCounter).toBe(0); + + TestBed.flushEffects(); + expect(effectCounter).toBe(0); + + fixture.componentInstance.counter.set(2); + TestBed.flushEffects(); + expect(effectCounter).toBe(0); + }); }); });