如何用Signal Input替代Angular组件中的@Input() setter?
用Angular Signal重构双向搜索组件(移除@Input() setter)
重构后的完整组件代码
inpage-search.component.ts
import { ChangeDetectionStrategy, Component, effect, input, output, signal, toObservable } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { ClarityModule } from '@clr/angular'; import { TranslateModule } from '@ngx-translate/core'; import { debounceTime, distinctUntilChanged } from 'rxjs'; @Component({ selector: 'shared-inpage-search', standalone: true, imports: [FormsModule, TranslateModule, ClarityModule], templateUrl: './inpage-search.component.html', styleUrl: './inpage-search.component.css', changeDetection: ChangeDetectionStrategy.OnPush, }) export class InpageSearchComponent { readonly placeholder = input<string>(); readonly label = input<string>(); // 外部传入的搜索词输入Signal(只读) readonly searchTermInput = input<string>(''); // 内部维护的可写Signal,用于绑定输入框 private readonly _searchTerm = signal<string>(this.searchTermInput()); // 对外暴露的只读Signal(可选,供外部读取当前值) readonly searchTerm = this._searchTerm.asReadonly(); readonly searchTermChange = output<string>(); constructor() { // 监听外部输入变化,同步到内部状态 effect(() => { const externalTerm = this.searchTermInput(); if (externalTerm !== this._searchTerm()) { this._searchTerm.set(externalTerm); // 外部设置时直接触发输出,和原setter行为一致 this.searchTermChange.emit(externalTerm); } }); // 监听内部输入框变化,防抖后输出 toObservable(this._searchTerm) .pipe(distinctUntilChanged(), debounceTime(200)) .subscribe(term => { // 避免外部设置值时重复触发防抖输出 if (term !== this.searchTermInput()) { this.searchTermChange.emit(term); } }); } // 输入框值变化时更新内部Signal onSearchTermChange(searchTerm: string) { this._searchTerm.set(searchTerm); } }
inpage-search.component.html
<clr-input-container> <label>{{ label() }}</label> <input clrInput class="search-term-input" [placeholder]="placeholder()" [ngModel]="searchTerm()" (ngModelChange)="onSearchTermChange($event)" /> </clr-input-container>
关键重构点说明
替换@Input() setter为输入Signal
- 用
input<string>('')创建只读的searchTermInput接收外部传入值,内部用可写Signal_searchTerm维护输入框状态(输入Signal本身不可修改)。
- 用
同步外部输入到内部状态
- 通过
effect监听外部输入Signal的变化,当值不一致时更新内部状态并触发输出,完全复刻原setter的行为。
- 通过
用Signal替代Subject实现防抖
- 借助
toObservable()将内部Signal转换为Observable,配合RxJS操作符实现防抖去重,彻底移除原有的Subject,贴合Signal使用范式。
- 借助
避免循环更新
- 在防抖输出时判断当前值是否与外部输入一致,防止外部设置值后触发重复输出,避免不必要的循环更新。
组件使用示例
外部组件可通过双向绑定方式使用:
<shared-inpage-search [label]="'搜索'" [placeholder]="'输入关键词'" [searchTermInput]="externalSearchTerm()" (searchTermChange)="externalSearchTerm.set($event)" ></shared-inpage-search>
内容的提问来源于stack exchange,提问作者mandrag.ora
相关产品推荐
相关产品推荐

