Angular 6中OnPush组件为何因array.push更新视图?
解释Angular OnPush策略下push数组后子组件更新的现象
嘿,我来帮你理清这个困惑!你遇到的情况其实是因为对ChangeDetectionStrategy.OnPush的触发条件理解得不够全面,咱们一步步拆解:
首先纠正一个常见误解:OnPush的触发条件不止是输入引用变化
很多人以为OnPush组件只有在输入属性的引用发生变化时才会触发变更检测,但实际上Angular会在以下几种情况触发OnPush组件的变更检测:
- 组件的输入属性引用发生变化
- 组件自身触发了DOM事件(比如按钮点击、输入框输入等)
- 使用
async管道时收到了新的数据流 - 手动调用了
ChangeDetectorRef.markForCheck()或detectChanges()
回到你的案例分析
当你点击Add New Car按钮时:
- 按钮的点击事件触发了
RaceComponent的事件处理函数,Angular会自动启动当前组件的变更检测周期——这和你用不用OnPush无关,只要是组件内部的DOM事件,都会触发这个逻辑,所以你会看到RACE CHECK的打印。 - 在
RaceComponent的变更检测过程中,Angular会遍历它的模板:- 对于已经存在的
<app-exp-car>组件(id为1、2、3的那些):Angular会检查它们的@Input() car引用是否变化——这里原有的car对象引用没改,所以OnPush策略下,Angular不会对这些子组件进行视图更新(如果car的属性没有修改的话)。但ngDoCheck钩子会执行,因为它是变更检测周期的一部分,不管组件是不是OnPush,只要被纳入变更检测树的遍历,就会触发这个钩子,所以你会看到每个Car组件的CAR X CHECK打印。 - 对于
*ngFor指令:Angular会对比数组的长度和元素,发现新增了一个元素,所以会创建新的<app-exp-car>组件实例并渲染,这部分是正常的视图更新。
- 对于已经存在的
验证视图是否真的更新
你可以做个小测试:在CarComponent的模板里只展示car.color,点击Add New Car按钮后,原来的三个Car组件的颜色不会变化,只有新添加的红色Car会显示——这说明旧组件的视图并没有更新,只是ngDoCheck钩子被执行了而已。
如果想严格遵循“只有数组引用变化才触发更新”
如果希望只有当数组引用改变时才让RaceComponent触发变更检测(即使是点击事件),你可以通过创建新数组的方式更新:
addNewCar() { // 解构原数组,创建新数组并添加元素 this.cars = [...this.cars, { id: 4, color: 'red' }]; }
不过要注意,即使这样,点击按钮还是会触发RaceComponent的变更检测周期,但因为数组引用变化了,OnPush会确保变更检测正常进行。
内容的提问来源于stack exchange,提问作者Naor Talmor
相关产品推荐
相关产品推荐

