Angular向数组push新元素时@Input属性变更未被检测问题
问题核心原因
Angular的@Input装饰器的变更检测默认是引用对比,只有当输入属性绑定的变量内存引用发生变化时,才会触发对应的setter方法。
你出现新增不触发、删除触发的情况,大概率是删除数组元素时你无意中生成了新的数组引用,而新增元素时是直接在原数组上执行push/unshift等方法修改,数组引用没有变化,所以setter不会执行。
解决方案(不需要使用
ngOnChanges) 方案一:父组件采用不可变方式更新数组(最推荐,无需修改子组件代码)
不管是新增还是删除数组元素,都直接生成新的数组实例,替换原变量,这样引用每次变更都会触发子组件的setter:
- 新增元素时不要直接
push,改为:
// 原有写法:this.dataSource.push(newItem) this.dataSource = [...this.dataSource, newItem]
- 删除元素时也保持返回新数组的写法:
// 原有如果是splice修改原数组的写法,改为filter this.dataSource = this.dataSource.filter(item => item.id !== 要删除的元素id)
方案二:子组件用IterableDiffers监听数组内部变化(无需修改父组件逻辑)
如果父组件的数组更新逻辑没法改,你可以在子组件中使用Angular内置的IterableDiffers工具,和*ngFor的数组检测逻辑一致,不管数组引用有没有变,都能检测到内部元素的增删改:
子组件代码示例:
import { IterableDiffers, OnInit, DoCheck } from '@angular/core'; export class VerticalTabsComponent implements OnInit, DoCheck { private _dataSource: any[]; private differ: any; constructor(private differs: IterableDiffers) {} ngOnInit() { // 初始化数组对比器 this.differ = this.differs.find([]).create(); } ngDoCheck() { // 每次变更检测周期检查数组变化 const changes = this.differ.diff(this._dataSource); if (changes) { // 这里写你原本要在setter里执行的逻辑,数组有变化就会触发 console.log('dataSource发生了变化', changes); debugger; } } get dataSource(): any { return this._dataSource; } @Input() set dataSource(value: any) { this._dataSource = value; // 引用变化的时候还是会触发这里的逻辑 } }
这个方案只需要给需要监听数组变化的dataSource单独加检测逻辑,不需要处理其他大量的@Input属性,符合你的要求。
内容的提问来源于stack exchange,提问作者Devang Patel
相关产品推荐
相关产品推荐

