angular-core

安装量: 65
排名: #11597

安装

npx skills add https://github.com/gentleman-programming/gentleman-skills --skill angular-core

Standalone Components (REQUIRED)

Components are standalone by default. Do NOT set standalone: true.

@Component({ selector: 'app-user', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: ... }) export class UserComponent {}

Input/Output Functions (REQUIRED) // ✅ ALWAYS: Function-based readonly user = input.required(); readonly disabled = input(false); readonly selected = output(); readonly checked = model(false); // Two-way binding

// ❌ NEVER: Decorators @Input() user: User; @Output() selected = new EventEmitter();

Signals for State (REQUIRED) readonly count = signal(0); readonly doubled = computed(() => this.count() * 2);

// Update this.count.set(5); this.count.update(prev => prev + 1);

// Side effects effect(() => localStorage.setItem('count', this.count().toString()));

NO Lifecycle Hooks (REQUIRED)

Signals replace lifecycle hooks. Do NOT use ngOnInit, ngOnChanges, ngOnDestroy.

// ❌ NEVER: Lifecycle hooks ngOnInit() { this.loadUser(); }

ngOnChanges(changes: SimpleChanges) { if (changes['userId']) { this.loadUser(); } }

// ✅ ALWAYS: Signals + effect readonly userId = input.required(); readonly user = signal(null);

private userEffect = effect(() => { // Runs automatically when userId() changes this.loadUser(this.userId()); });

// ✅ For derived data, use computed readonly displayName = computed(() => this.user()?.name ?? 'Guest');

When to Use What Need Use React to input changes effect() watching the input signal Derived/computed state computed() Side effects (API calls, localStorage) effect() Cleanup on destroy DestroyRef + inject() // Cleanup example private readonly destroyRef = inject(DestroyRef);

constructor() { const subscription = someObservable$.subscribe(); this.destroyRef.onDestroy(() => subscription.unsubscribe()); }

inject() Over Constructor (REQUIRED) // ✅ ALWAYS private readonly http = inject(HttpClient);

// ❌ NEVER constructor(private http: HttpClient) {}

Native Control Flow (REQUIRED) @if (loading()) { } @else { @for (item of items(); track item.id) { } @empty {

No items

} }

@switch (status()) { @case ('active') { Active } @default { Unknown } }

RxJS - Only When Needed

Signals are the default. Use RxJS ONLY for complex async operations.

Use Signals Use RxJS Component state Combining multiple streams Derived values Debounce/throttle Simple async (single API call) Race conditions Input/Output WebSockets, real-time Complex error retry logic // ✅ Simple API call - use signals readonly user = signal(null); readonly loading = signal(false);

async loadUser(id: string) { this.loading.set(true); this.user.set(await firstValueFrom(this.http.get(/api/users/${id}))); this.loading.set(false); }

// ✅ Complex stream - use RxJS readonly searchResults$ = this.searchTerm$.pipe( debounceTime(300), distinctUntilChanged(), switchMap(term => this.http.get(/api/search?q=${term})) );

// Convert to signal when needed in template readonly searchResults = toSignal(this.searchResults$, { initialValue: [] });

Zoneless Angular (REQUIRED)

Angular is zoneless. Use provideZonelessChangeDetection().

bootstrapApplication(AppComponent, { providers: [provideZonelessChangeDetection()] });

Remove ZoneJS:

npm uninstall zone.js

Remove from angular.json polyfills: zone.js and zone.js/testing.

Zoneless Requirements Use OnPush change detection Use signals for state (auto-notifies Angular) Use AsyncPipe for observables Use markForCheck() when needed Resources https://angular.dev/guide/signals https://angular.dev/guide/templates/control-flow https://angular.dev/guide/zoneless

返回排行榜