在使用Angular OnPush ChangeDetection时,ngFor存在问题。
这是我的代码:
app.state.ts
export class Node {
title: string;
}
export class Tree {
nodes: Array<Node>
}
home.component.ts
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HomeComponent implements OnInit {
tree$: Observable<Tree>;
ngOnInit() {
this.tree$ = this.store.select(state => state.tree);
}
}
home.component.html
Number of nodes: {{ (tree$ | async).nodes.length }}
<div *ngFor="let node of (tree$ | async).nodes" class="node-list">
{{ node.title }}
</div>
默认情况下,节点数组为空。当我调度将新节点添加到 nodes 数组中的操作时。模板中的节点数已更改,但是节点列表仍然为空。
我不明白为什么。你有什么主意吗?谢谢!
更新 通过在包含节点列表的容器中添加* ngIf,它可以正常工作。
<div *ngIf="tree$">
<div *ngFor="let node of (tree$ | async).nodes" class="node-list">
{{ node.title }}
</div>
</div>
但是我仍然不明白为什么。您能解释一下这种行为吗?
答案 0 :(得分:1)
(tree $ | async)。如果未初始化树,则节点将导致异常。
尝试
<ng-container *ngIf="tree$ | async as tree">
Number of nodes: {{ tree.nodes.length }}
<div *ngFor="let node of tree.nodes" class="node-list">
{{ node.title }}
</div>
</ng-container>
对于在分派第一个操作之前未定义树的情况,这不会崩溃。
答案 1 :(得分:0)
ChangeDetectionStrategy.OnPush
旨在通过忽略内部对组件及其指令的更改的检查来提高组件的性能。这只会检查某些转移装饰器(例如@Input
)的更改。因此,在这种情况下,即使我们将tree$
声明为async
,该组件也无法检测到这是要更新为DOM
的更新。模板中节点的数量发生了变化,因为length
是Javascript中任何Array
的不可变内置属性,每当其值更改时,该(tree$ | async).nodes
就会分配给不同的存储位置。相反,Store
即使更改了其属性也被引用到相同的存储位置。
您可以检查几个选项来修复它:
a+b[0].tolist()
-Angular2 ngFor OnPush Change Detection with Array Mutations