Angular 4中父组件数据变更时如何强制子组件重载数据与视图?
解决Angular 4子组件数据不更新的问题
嘿,我完全懂你遇到的这个头疼问题——父组件明明更新了人员的百分比属性,子组件的视图却纹丝不动,连ngOnChanges都没触发,对吧?这其实是Angular变更检测机制的一个常见“坑”,我来给你拆解清楚原因和可行的解决方案:
为什么ngOnChanges没生效?
Angular的ngOnChanges钩子只会在输入属性的引用发生变化时触发。你现在只是修改了person对象内部的percent属性,整个person对象的引用并没有改变(还是原来那个对象),所以Angular会认为这个输入属性没变化,自然不会调用ngOnChanges,子组件里的this.percent也就一直停留在ngOnInit初始化时的值。
几种可行的解决方案
方案1:用ngDoCheck手动检测属性变化
如果你不想改动父组件的代码,可以在子组件里实现ngDoCheck钩子,手动对比person.percent的新旧值,一旦发现变化就更新this.percent:
import { Component, Input, OnInit, DoCheck } from '@angular/core'; import { Person } from './person.model'; @Component({ selector: 'person', template: '<div>{{ percent }}%</div>' }) export class PersonComponent implements OnInit, DoCheck { @Input() person: Person; percent: number; private _oldPercent: number; // 存储上一次的percent值 ngOnInit() { this._oldPercent = this.person.percent; this.percent = this.person.percent; } ngDoCheck() { // 对比当前percent和旧值,不一样就更新 if (this.person.percent !== this._oldPercent) { this._oldPercent = this.person.percent; this.percent = this.person.percent; } } }
方案2:更新父组件中person对象的引用(推荐)
这种方法更符合Angular的不可变数据理念,通过创建新的Person对象替换原对象,让引用发生变化,这样ngOnChanges就能正常触发了:
修改父组件的setPercent方法:
setPercent() { this.people = this.people.map(person => { const newPercent = Math.round((person.value / this.total_amount) * 100); // 用对象展开运算符创建新的Person对象,改变引用 return { ...person, percent: newPercent }; }); }
然后子组件里的ngOnChanges就能正常工作了,你可以在里面更新this.percent:
import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { Person } from './person.model'; @Component({ selector: 'person', template: '<div>{{ percent }}%</div>' }) export class PersonComponent implements OnInit, OnChanges { @Input() person: Person; percent: number; ngOnInit() { this.percent = this.person.percent; } ngOnChanges(changes: SimpleChanges) { // 当person引用变化时,更新percent if (changes.person) { this.percent = this.person.percent; } } }
方案3:手动触发变更检测(不推荐,除非必要)
如果上面两种方法都不适合你的场景,你可以在子组件中注入ChangeDetectorRef,手动通知Angular检测变化:
import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core'; import { Person } from './person.model'; @Component({ selector: 'person', template: '<div>{{ percent }}%</div>' }) export class PersonComponent implements OnInit { @Input() person: Person; percent: number; constructor(private cdr: ChangeDetectorRef) {} ngOnInit() { this.percent = this.person.percent; } // 如果你能感知到person.percent变化的时机,可以调用这个方法 updatePercent() { this.percent = this.person.percent; this.cdr.markForCheck(); // 通知Angular检测变化 } }
不过这种方法尽量少用,因为频繁手动触发可能会影响应用性能。
内容的提问来源于stack exchange,提问作者Joshua Majebi
相关产品推荐
相关产品推荐

