Angular中ngOnChanges未检测到Input属性变更的原因咨询
问题场景
我编写了一个Angular子组件,实现了OnInit、OnDestroy、OnChanges接口,通过@Input()装饰的filters属性接收父组件传递的FilterMetadata类型数据。父组件以<request-Component [filters]='filtersData'></request-Component>方式引入子组件,并通过setFiltersData方法更新filtersData。但父组件更新filtersData时,子组件的ngOnChanges钩子未触发。我已通过给Input属性添加getter和setter解决问题,现想了解ngOnChanges未检测到变更的具体原因。
相关代码
子组件代码
@Component({ selector: 'request-Component' templateUrls: './request.component.html' styleUrls: ['./request.component.scss'] }) export class ChildComponent implements OnInit, OnDestroy, OnChanges { @Input() filters: FilterMetadata; constructor(private service: RequestService){} ngOnInit(): void {this.service.GetRequests(this.filters);} ngOnChanges(changes: SimpleChanges): void { console.info('ngOnChanges: ', changes['filters']); this.service.GetRequests(this.filters); } }
FilterMetadata接口
export default interface FilterMetadata{ country: string; state: string; city: string; }
父组件更新filtersData的方法
setFiltersData() { this.FiltersData = { country: 'testCountry', state: 'testState', city: 'testCity' } }
核心原因
Angular的ngOnChanges钩子仅在输入属性的引用发生改变时才会触发,它不会自动检测对象内部属性的修改,具体分两种情况:
直接修改对象内部属性:如果之前你更新
filtersData时,是直接修改现有对象的属性(比如this.filtersData.country = 'newValue'),而非像当前代码这样给filtersData赋值一个全新的对象,那么Angular会认为这个输入属性的内存引用没有变化,因此不会触发ngOnChanges。因为对象是引用类型,修改内部属性不会改变它在内存中的地址,默认变更检测机制捕捉不到这种内部变化。变量名大小写不一致(潜在笔误):你的父组件模板绑定的是
filtersData(小写f),但更新方法里赋值的是this.FiltersData(大写F)。如果这是实际代码中的疏忽,那么父组件的filtersData根本没被更新,子组件自然收不到变更通知。不过你已经通过getter/setter解决问题,这个可能不是主要原因,但也是常见的排查点。
而你用getter和setter能解决问题,是因为setter会在每次属性值被修改时触发——不管是引用替换还是内部属性修改(若要检测内部属性变化,需要在setter里手动比较对象内容)。当给filters添加setter后,只要父组件传递的filtersData有变化,setter就会执行,从而实现预期逻辑。
内容的提问来源于stack exchange,提问作者soumyadeb ghoshal

