mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-14 00:23:04 +08:00
feat: salvage Angular developer skill
This commit is contained in:
committed by
Affaan Mustafa
parent
14816289ba
commit
456bbd12e5
83
skills/angular-developer/references/effects.md
Normal file
83
skills/angular-developer/references/effects.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Side Effects with `effect` and `afterRenderEffect`
|
||||
|
||||
In Angular, an **effect** is an operation that runs whenever one or more signal values it tracks change.
|
||||
|
||||
## When to use `effect`
|
||||
|
||||
Effects are intended for syncing signal state to imperative, non-signal APIs.
|
||||
|
||||
**Valid Use Cases:**
|
||||
|
||||
- Logging analytics.
|
||||
- Syncing state to `localStorage` or `sessionStorage`.
|
||||
- Performing custom rendering to a `<canvas>` or 3rd-party charting library.
|
||||
|
||||
**CRITICAL RULE: DO NOT use effects to propagate state.**
|
||||
If you find yourself using `.set()` or `.update()` on a signal _inside_ an effect to keep two signals in sync, you are making a mistake. This causes `ExpressionChangedAfterItHasBeenChecked` errors and infinite loops. **Always use `computed()` or `linkedSignal()` for state derivation.**
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Effects execute asynchronously during the change detection process. They always run at least once.
|
||||
|
||||
```ts
|
||||
import { Component, signal, effect } from '@angular/core';
|
||||
|
||||
@Component({...})
|
||||
export class Example {
|
||||
count = signal(0);
|
||||
|
||||
constructor() {
|
||||
// Effect must be created in an injection context (e.g., a constructor)
|
||||
effect((onCleanup) => {
|
||||
console.log(`Count changed to ${this.count()}`);
|
||||
|
||||
const timer = setTimeout(() => console.log('Timer finished'), 1000);
|
||||
|
||||
// Cleanup function runs before the next execution, or when destroyed
|
||||
onCleanup(() => clearTimeout(timer));
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## DOM Manipulation with `afterRenderEffect`
|
||||
|
||||
Standard `effect` runs _before_ Angular updates the DOM. If you need to manually inspect or modify the DOM based on a signal change (e.g., integrating a 3rd party UI library), use `afterRenderEffect`.
|
||||
|
||||
`afterRenderEffect` runs after Angular has finished rendering the DOM.
|
||||
|
||||
### Render Phases
|
||||
|
||||
To prevent reflows (forced layout thrashing), `afterRenderEffect` forces you to divide your DOM reads and writes into specific phases.
|
||||
|
||||
```ts
|
||||
import { Component, afterRenderEffect, viewChild, ElementRef } from '@angular/core';
|
||||
|
||||
@Component({...})
|
||||
export class Chart {
|
||||
canvas = viewChild.required<ElementRef>('canvas');
|
||||
|
||||
constructor() {
|
||||
afterRenderEffect({
|
||||
// 1. Read from the DOM
|
||||
earlyRead: () => {
|
||||
return this.canvas().nativeElement.getBoundingClientRect().width;
|
||||
},
|
||||
// 2. Write to the DOM (receives the result of the previous phase)
|
||||
write: (width) => {
|
||||
// NEVER read from the DOM in the write phase.
|
||||
setupChart(this.canvas().nativeElement, width);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Available Phases (executed in this order):**
|
||||
|
||||
1. `earlyRead`
|
||||
2. `write` (Never read here)
|
||||
3. `mixedReadWrite` (Avoid if possible)
|
||||
4. `read` (Never write here)
|
||||
|
||||
_Note: `afterRenderEffect` only runs on the client, never during Server-Side Rendering (SSR)._
|
||||
Reference in New Issue
Block a user