angular 21 升级使用 signals 方案笔记
signals 提供新的数据绑定和变更检测机制。从 angular 17 就开始引入了,
优点:
- 更精细的响应检测。
缺点:
- 变化太大,
signal
基本的绑定,可读可写。
angular 17 之前:
@Component({
standalone: false,
selector: 'app-example',
template: `{{ text }}`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
public text = 'hi';
public tap() {
this.text = 'hello';
}
}
angular 17 之后:
@Component({
standalone: false,
selector: 'app-example',
template: `{{ text() }}`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
public readonly text = signal<string>('hi');
public tap() {
this.text.set('hello');
this.text.update(v => {
return 'hello';
});
}
}
注意
- 使用
set或update更新值。 - 当值是对象时,使用
update更新某个属性,必须生成新的对象,才能有效检测
// 正确使用 this.data.update(v => { v.a = 3; return {...v}; // 或者 return {...v, a: 3}; });
3. 当值时数组时,使用 `update` 新增或删除某一项
```ts
public readonly items = signal<number[]>([]);
// 错误示范
this.items.update(v => {
v.push(1);
v.pop();
return v;
});
// 正确使用
this.items.update(v => {
v.push(1);
return [...v];
// 或者
return [...v, 1];
});
input、output、model
input 相当于 @Input(), 但是可读不可写,增加了自定义转换
output 相当于 @Output(),
model 相对于 @Input() + @Output(),可读可写
angular 17 之前:
@Component({
standalone: false,
selector: 'app-example',
template: `{{ text }}`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
@Input() public text = 'hi';
@Output() public textChange = new EventEmitter();
}
angular 17 之后:
@Component({
standalone: false,
selector: 'app-example',
template: `{{ text() }}`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
public readonly text = input('hi', {tranform: parseInt});
public readonly textChange = output();
public readonly text = model('');
}
form
@Component({
standalone: false,
selector: 'app-example',
template: `<input type="number" [field]="form.a">`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
public readonly form = form(sinal({
a: 1
}), schemaPath => {
required(schemaPath.a);
})
}
使用 [field] 精选表单绑定,不能自定义 name 属性,
注意
- 表单
name属性自动生成 类似于[项目名].form1.a,如果介意name,则推荐使用 原本FormBuilder方式 - 一些值限制的变化,
select的值为string,input type=checkbox为boolean,type=number为number, 其他则必须为string
effect
检测 值的变化,替代 ngOnChanges
@Component({
standalone: false,
selector: 'app-example',
template: `{{ text() }}`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
public readonly text = model('');
constructor() {
let previousText = '';
effect(() => {
this.text();
// 当 text 发生变化时,TODO
previousText = this.text(); // 使用此方法实现值的前后变化检测
});
}
}
computed
关联变化,提供值变化前后对比
angular 17 之前:
@Component({
standalone: false,
selector: 'app-example',
template: `{{ text }} {{ twoText }}`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
public text = 'hi';
public get twoText() {
return this.text + ', two';
}
public tap() {
this.text = 'hello';
}
}
angular 17 之后:
@Component({
standalone: false,
selector: 'app-example',
template: `{{ text() }} {{ twoText() }}`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent {
public readonly text = signal<string>('hi');
public readonly twoText = computed(() => {
return this.text() + ', two';
});
public tap() {
this.text.set('hello');
this.text.update(v => {
return 'hello';
});
}
}
与 signals 使用时失效的旧方法
@HostBinding 无法与 signal 等使用
可以使用 effect 同步或
@Component({
standalone: false,
selector: 'app-example',
template: ``,
styleUrls: ['./example.component.scss'],
host: {
'[class.open]': 'toggle()'
}
})
export class ExampleComponent {
public readonly toggle = model(false);
}
转载请保留原文链接: https://zodream.cn/blog/id/270.html