在 child 组件属性中更改 @Input() 会阻止 parent 组件的进一步更新
Changing @Input() in child compoent properties prevents further updates from parent component
我有 2 个组件 - Parent 和 Child。请参阅 stackblitz demo
Parent 的模板如下所示 -
单击 'Show Child' 时,isChild1Visible 设置为 true,导致 Child 组件显示其模板。
当您单击 'Hide me' 时,Child 组件将 isVisible 设置为 false,使其隐藏。现在,当再次单击 'Show Child' 时,不会显示 child 组件。
我在 Child 组件中添加 ngOnChanges() 来查看变化检测,但是我看到了下面的内容
child组件初始化时:
第一次点击'Show me'后
单击 'Hide me' 后,即使稍后单击 'Show me',ngOnChanges() 也不会打印任何内容。
那么,为什么在 child 组件中更新输入 属性 后更改检测停止工作?
问题
第一次设置 isChild1Visible
时,通过单向绑定它还会将 child isVisible
设置为 true。
从内部,您将 isVisible
设置为 false,因此 div 消失,因为您有 *ngIf="isVisible"
。
不过,外层的isVisible
还是true
!
当您再次点击外部按钮时,由于值保持不变,因此没有检测到任何变化,因此没有任何内容传递给 child。
看到这个 stackblitz demo 两个布尔值都暴露了。
选项 1:明确监听输出
如果你想从外部控制一个组件,你应该把逻辑放在外面。
一种可能的方法是在您的 child 上添加一个 @Output
,这是一个 EventEmitter
,当您想要关闭 child.
parent 将侦听该事件并执行某些操作,例如将 isVisible
设置为 false。
你可以在this updated stackblitz上看到它。
选项 2:Two-way 绑定
类似于解决方案选项 1,您可以创建一个与您的输入同名的发射器,以 Change
结尾并在那里触发您的更改。
在这种情况下,您只需将绑定替换为 [(isVisible)]="isChild1Visible"
并将 isVisibleChange
添加为 @Output EventEmitter<any>
。
演示 stackblitz。
由于数据 isChild1Visible 是作为基本类型(布尔值)传递的,它将“按值传递”。
因此,如果传递对象、数组等,则为引用传递,而对于数字等原始类型,则为值传递。
在不添加任何额外输出的情况下尝试此操作:
MyAppChild1Component
export class MyAppChild1Component implements OnInit {
@Input() isVisible;
constructor() {}
ngOnInit() {}
onClick() {
this.isVisible.value = false;
}
}
<div *ngIf="isVisible.value">
<span>
Child
</span>
<button (click)="onClick()">Hide me</button>
</div>
AppComponent
export class AppComponent {
isChild1Visible = { value: false };
ngOnInit() {}
onShowChild() {
this.isChild1Visible.value = true;
}
}
<div>
<p>Parent</p>
<button (click)="onShowChild()">show Child</button>
<app-my-app-child1 [isVisible]="isChild1Visible"></app-my-app-child1>
</div>
发生这种情况是因为 app.component 中的 isChild1Visible
在子组件设置时未更新
isVisible
.
首先点击onShowChild()
isChild1Visible
= 真
isVisible
= 真
第二次点击子 onClick()
isVisible
= false;
isChild1Visible
= 真
第二次点击 onShowChild()
isChild1Visible
= true // => 这里没有变化
isVisible
= 假
由于 isChild1Visible
的值未更改,因此 Angular 不会更新任何内容。
为了触发变更检测并保持值同步,您需要使用 Two-Way binding。
<app-my-app-child1 [(isVisible)]="isChild1Visible"></app-my-app-child1>
export class MyAppChild1Component implements OnInit {
@Input() isVisible;
@Output() isVisibleChange = new EventEmitter<boolean>();
constructor() {}
ngOnInit() {}
onClick() {
this.isVisibleChange.emit(!this.isVisibleChange);
}
}
我有 2 个组件 - Parent 和 Child。请参阅 stackblitz demo
Parent 的模板如下所示 -
单击 'Show Child' 时,isChild1Visible 设置为 true,导致 Child 组件显示其模板。
当您单击 'Hide me' 时,Child 组件将 isVisible 设置为 false,使其隐藏。现在,当再次单击 'Show Child' 时,不会显示 child 组件。
我在 Child 组件中添加 ngOnChanges() 来查看变化检测,但是我看到了下面的内容
child组件初始化时:
第一次点击'Show me'后
单击 'Hide me' 后,即使稍后单击 'Show me',ngOnChanges() 也不会打印任何内容。
那么,为什么在 child 组件中更新输入 属性 后更改检测停止工作?
问题
第一次设置 isChild1Visible
时,通过单向绑定它还会将 child isVisible
设置为 true。
从内部,您将 isVisible
设置为 false,因此 div 消失,因为您有 *ngIf="isVisible"
。
不过,外层的isVisible
还是true
!
当您再次点击外部按钮时,由于值保持不变,因此没有检测到任何变化,因此没有任何内容传递给 child。
看到这个 stackblitz demo 两个布尔值都暴露了。
选项 1:明确监听输出
如果你想从外部控制一个组件,你应该把逻辑放在外面。
一种可能的方法是在您的 child 上添加一个 @Output
,这是一个 EventEmitter
,当您想要关闭 child.
parent 将侦听该事件并执行某些操作,例如将 isVisible
设置为 false。
你可以在this updated stackblitz上看到它。
选项 2:Two-way 绑定
类似于解决方案选项 1,您可以创建一个与您的输入同名的发射器,以 Change
结尾并在那里触发您的更改。
在这种情况下,您只需将绑定替换为 [(isVisible)]="isChild1Visible"
并将 isVisibleChange
添加为 @Output EventEmitter<any>
。
演示 stackblitz。
由于数据 isChild1Visible 是作为基本类型(布尔值)传递的,它将“按值传递”。
因此,如果传递对象、数组等,则为引用传递,而对于数字等原始类型,则为值传递。
在不添加任何额外输出的情况下尝试此操作:
MyAppChild1Component
export class MyAppChild1Component implements OnInit {
@Input() isVisible;
constructor() {}
ngOnInit() {}
onClick() {
this.isVisible.value = false;
}
}
<div *ngIf="isVisible.value">
<span>
Child
</span>
<button (click)="onClick()">Hide me</button>
</div>
AppComponent
export class AppComponent {
isChild1Visible = { value: false };
ngOnInit() {}
onShowChild() {
this.isChild1Visible.value = true;
}
}
<div>
<p>Parent</p>
<button (click)="onShowChild()">show Child</button>
<app-my-app-child1 [isVisible]="isChild1Visible"></app-my-app-child1>
</div>
发生这种情况是因为 app.component 中的 isChild1Visible
在子组件设置时未更新
isVisible
.
首先点击onShowChild()
isChild1Visible
= 真isVisible
= 真
第二次点击子 onClick()
isVisible
= false;isChild1Visible
= 真
第二次点击 onShowChild()
isChild1Visible
= true // => 这里没有变化isVisible
= 假
由于 isChild1Visible
的值未更改,因此 Angular 不会更新任何内容。
为了触发变更检测并保持值同步,您需要使用 Two-Way binding。
<app-my-app-child1 [(isVisible)]="isChild1Visible"></app-my-app-child1>
export class MyAppChild1Component implements OnInit {
@Input() isVisible;
@Output() isVisibleChange = new EventEmitter<boolean>();
constructor() {}
ngOnInit() {}
onClick() {
this.isVisibleChange.emit(!this.isVisibleChange);
}
}