angular-signals

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Angular Signals

Angular Signals

Version: Angular 16+ (2025) Tags: Reactivity, State Management, Signals API
版本: Angular 16+(2025) 标签: 响应式、状态管理、Signals API
参考资料: Angular SignalsAPI 参考

API Changes

API 变更

This section documents version-specific API changes.
  • NEW: Angular 19 Resource API — New way to handle async data with built-in loading/error states
  • NEW: linkedSignal() — Creates a signal linked to external sources with getter/setter source
  • NEW: Signal inputs — Use
    input()
    and
    input.required()
    for reactive component inputs
  • NEW:
    toSignal()
    and
    toObservable()
    — Bridge between RxJS and Signals
  • NEW:
    effect()
    improvements — Better cleanup with
    onCleanup
    callback
  • NEW: Zoneless change detection — Works seamlessly with Signals
本节记录不同版本的特定API变更。
  • 新增:Angular 19 Resource API — 处理异步数据的新方式,内置加载/错误状态
  • 新增:linkedSignal() — 创建与外部源关联的signal,支持getter/setter 来源
  • 新增:Signal 输入 — 使用
    input()
    input.required()
    实现响应式组件输入
  • 新增:
    toSignal()
    toObservable()
    — 连通RxJS与Signals的桥梁
  • 新增:
    effect()
    优化 — 借助
    onCleanup
    回调实现更完善的清理逻辑
  • 新增:无Zone变更检测 — 可与Signals无缝协同

Best Practices

最佳实践

  • Use
    computed()
    for derived state — Never use
    effect()
    for deriving values
ts
// ✅ DO THIS - derived state
totalPrice = computed(() => {
  return this.items().reduce((sum, item) => sum + item.price, 0);
});

// ❌ DON'T - side effects in computed
badComputed = computed(() => {
  const data = this.data();
  this.logService.log(data); // Side effect - don't do this!
});
  • Use
    signal()
    for writable state
ts
count = signal(0);

// Update with set()
count.set(5);

// Update with update()
count.update(value => value + 1);

// Update with mutate() for objects
user.update(u => ({ ...u, name: 'New Name' }));
  • Use
    effect()
    only for side effects
ts
effect(() => {
  analytics.track('cart-updated', {
    itemCount: this.items().length
  });
});
  • Always cleanup effects to prevent memory leaks
ts
effect((onCleanup) => {
  const timer = setTimeout(() => { /* ... */ }, 300);
  onCleanup(() => clearTimeout(timer));
});
  • Use Signal Inputs instead of traditional @Input()
ts
// Modern signal inputs (Angular 17+)
userId = input<string>('');
user = input.required<User>();

// Computed based on input
greeting = computed(() => `Hello, ${this.user()?.name}`);
  • Use
    toSignal()
    for RxJS to Signal conversion
ts
// Convert Observable to Signal
users = toSignal(this.http.get('/api/users'), { initialValue: [] });
  • Don't nest effects — Can cause performance issues
  • Use equality functions for complex object comparisons
ts
user = signal<User | null>(null, {
  equal: (a, b) => a?.id === b?.id
});
  • Use Signals for UI state, RxJS for complex async — Signals and RxJS serve different purposes
  • 派生状态使用
    computed()
    — 绝对不要用
    effect()
    派生值
ts
// ✅ DO THIS - derived state
totalPrice = computed(() => {
  return this.items().reduce((sum, item) => sum + item.price, 0);
});

// ❌ DON'T - side effects in computed
badComputed = computed(() => {
  const data = this.data();
  this.logService.log(data); // Side effect - don't do this!
});
  • 可写状态使用
    signal()
ts
count = signal(0);

// Update with set()
count.set(5);

// Update with update()
count.update(value => value + 1);

// Update with mutate() for objects
user.update(u => ({ ...u, name: 'New Name' }));
  • effect()
    仅用于处理副作用
ts
effect(() => {
  analytics.track('cart-updated', {
    itemCount: this.items().length
  });
});
  • 始终清理effect以避免内存泄漏
ts
effect((onCleanup) => {
  const timer = setTimeout(() => { /* ... */ }, 300);
  onCleanup(() => clearTimeout(timer));
});
  • 使用Signal输入替代传统的@Input()
ts
// Modern signal inputs (Angular 17+)
userId = input<string>('');
user = input.required<User>();

// Computed based on input
greeting = computed(() => `Hello, ${this.user()?.name}`);
  • 使用
    toSignal()
    完成RxJS到Signal的转换
ts
// Convert Observable to Signal
users = toSignal(this.http.get('/api/users'), { initialValue: [] });
  • 不要嵌套effect — 可能引发性能问题
  • 复杂对象比较使用相等判断函数
ts
user = signal<User | null>(null, {
  equal: (a, b) => a?.id === b?.id
});
  • UI状态使用Signals,复杂异步逻辑使用RxJS — Signals和RxJS定位不同,各司其职