ChangeDectection OnPush:直接调用时未触发ngFor

时间:2019-07-08 03:16:02

标签: angular redux rxjs ngfor angular2-changedetection

在使用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>

但是我仍然不明白为什么。您能解释一下这种行为吗?

2 个答案:

答案 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即使更改了其属性也被引用到相同的存储位置。

您可以检查几个选项来修复它: