likes
comments
collection
share

Angular 17 信号 Signals

作者站长头像
站长
· 阅读数 10

一、简介

Angular Signals是一个系统,可以精细地跟踪整个应用程序中状态的使用方式和位置,从而使框架能够优化渲染更新。

信号 Signals 早已经不是新的概念了。在 PReact 和 solidjs 中早已经有了有了实践。

二、初始化项目

npm install -g @angular/cli

ng new my-app
cd my-app
ng serve --open

三、定义 Signals

  • HTML UI
<div style="font-size: 80px;">{{count()}}</div>
<div (click)="set()">设置</div>
<div (click)="add()">字体 +1</div>
<div (click)="del()">字体 -1</div>
  • TS 设置和更新 逻辑
import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  count = signal(1)
   // 设置大小
  set() { 
    this.count.set(123)
  }
  // 增加
  add() {
    this.count.update(c => c + 1)
  }
  // 减小
  del() {
    this.count.update(c => c - 1)
  }
}

四、计算 computed Singal

计算 Singal 不是可写的

  • html
<p>compouted works!</p>
<div>{{ count() }}</div>
<div>{{ countPlus() }}</div>
<button (click)="add()">+1</button>
  • TS 计算属性逻辑
import { Component, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-compouted',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './compouted.component.html',
  styleUrl: './compouted.component.css'
})
export class CompoutedComponent {
  count = signal(2)

  countPlus = computed(() => { return this.count() * this.count() })

  add() {
    this.count.update(() => this.count() * this.count())
  }

五、条件计算:动通过 computed 计算

const showCount = signal(false);
const count = signal(0);
const conditionalCount = computed(() => {
  if (showCount()) {
    return `The count is ${count()}.`;
  } else {
    return 'Nothing to see here!';
  }
});

六、effect 副作用

import { Component, computed, signal, effect } from '@angular/core';
import { CommonModule } from '@angular/common';
import { count } from 'rxjs';

@Component({
  selector: 'app-effect',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './effect.component.html',
  styleUrl: './effect.component.css',
})
export class EffectComponent {
  count = signal(12);
  countPlus = computed(() => this.count() * this.count());

  countEff = effect(() => {
    console.log(
      `The current count is: ${this.count()} and ${this.countPlus()}`
    );
  });
}

需要注意的是 effect 函数需要一个返回值,

七、onCleanup 清理(定时器)

effect((onCleanup) => {
  const user = currentUser();
  const timer = setTimeout(() => {
    console.log(`1 second ago, the user became ${user}`);
  }, 1000);
  onCleanup(() => {
    clearTimeout(timer);
  });
});

八、rxjs 可观察对象转信号

Angular 的@angular/core/rxjs-interop包提供了有用的实用程序来将Angular Signals与 RxJS Observables 集成。

  • html
<p>rxjs works!</p>
<div>{{counter()}}</div>
  • TS 逻辑
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { interval } from 'rxjs';
import { toSignal} from '@angular/core/rxjs-interop'
@Component({
  selector: 'app-rxjs',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './rxjs.component.html',
  styleUrl: './rxjs.component.css'
})
export class RxjsComponent {
   counterObservable = interval(1000);
  // Get a `Signal` representing the `counterObservable`'s value.
  counter = toSignal(this.counterObservable, {initialValue: 0});
}

九、rxjs 信号转可观察对象

import { Component, signal, effect } from '@angular/core';
import { CommonModule } from '@angular/common';
import { interval } from 'rxjs';
import { toSignal, toObservable } from '@angular/core/rxjs-interop'
@Component({
  selector: 'app-rxjs',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './rxjs.component.html',
  styleUrl: './rxjs.component.css'
})
export class RxjsComponent {
  counterObservable = interval(1000);
  // Get a `Signal` representing the `counterObservable`'s value.
  counter = toSignal(this.counterObservable, {initialValue: 0});


  num = signal(100)
  num$ = toObservable(this.num)
  numEff = effect(() => {
    this.num$.subscribe({
      next(v) {
        console.log(v)
      }
    })
  })
}

十、小结

本文主要关注 Angular 17 汇总关于信号的内容,使用 signal 函数传入值定义一个信号数据。使用 set 方法进行设置,使用 update 方法进行更新。当然 signal 支持计算方法,通过 computed 计算出一个新的值,或者依据其他的 signal 计算一个新的值。同时 angular 支持 effect 函数,用于处理副作用,你的定时器都可以通过 effect 的 onCleanup 方法进行清除。因为 Angular 支持 RxJS 信号也对可观察对象进行了支持,可以通过可观察对象对其进行相互转换。