209

如何强制组件在 Angular 2 中重新渲染?出于调试目的,我想强制一个组件重新渲染它的视图,这可能吗?

4

6 回答 6

245

渲染发生在更改检测之后。要强制进行更改检测,以便将已更改的组件属性值传播到 DOM(然后浏览器将在视图中呈现这些更改),这里有一些选项:

  • ApplicationRef.tick() - 类似于 Angular 1 的$rootScope.$digest()- 即检查完整的组件树
  • NgZone.run(callback) - 类似于$rootScope.$apply(callback)-- 即评估 Angular 2 区域内的回调函数。我认为,但我不确定,这最终会在执行回调函数后检查完整的组件树。
  • ChangeDetectorRef.detectChanges() - 类似于$scope.$digest()-- 即仅检查此组件及其子组件

您将需要导入然后将ApplicationRefNgZoneChangeDetectorRef注入到您的组件中。

对于您的特定情况,如果只有一个组件发生了更改,我会推荐最后一个选项。

于 2016-01-30T19:25:14.623 回答
52

tx,找到了我需要的解决方法:

  constructor(private zone:NgZone) {
    // enable to for time travel
    this.appStore.subscribe((state) => {
        this.zone.run(() => {
            console.log('enabled time travel');
        });
    });

运行 zone.run 将强制组件重新渲染

于 2016-01-30T18:42:29.367 回答
40

ChangeDetectorRef 方法

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

export class MyComponent {

    constructor(private cdr: ChangeDetectorRef) { }

    selected(item: any) {
        if (item == 'Department')
            this.isDepartment = true;
        else
            this.isDepartment = false;
        this.cdr.detectChanges();
    }

}
于 2018-05-22T16:56:53.717 回答
29

我使用 *ngIf 强制重新加载我的组件。

我容器内的所有组件都回到了完整的生命周期钩子。

在模板中:

<ng-container *ngIf="_reload">
    components here 
</ng-container>

然后在 ts 文件中:

public _reload = true;

private reload() {
    setTimeout(() => this._reload = false);
    setTimeout(() => this._reload = true);
}
于 2019-06-11T09:48:34.163 回答
15

此处的其他答案提供了触发更改检测周期的解决方案,该周期将更新组件的视图(与完全重新渲染不同)。

完全重新渲染,这将破坏和重新初始化组件(调用所有生命周期钩子和重建视图)可以使用ng-template,ng-containerViewContainerRef通过以下方式完成:

<div>
  <ng-container #outlet >
  </ng-container>
</div>

<ng-template #content>
  <child></child>
</ng-template>

然后在引用两者的组件中#outlet#content我们可以清除出口的内容并插入另一个子组件实例:

@ViewChild("outlet", {read: ViewContainerRef}) outletRef: ViewContainerRef;
@ViewChild("content", {read: TemplateRef}) contentRef: TemplateRef<any>;

private rerender() {
    this.outletRef.clear();
    this.outletRef.createEmbeddedView(this.contentRef);
}

此外,初始内容应插入AfterContentInit挂钩:

ngAfterContentInit() {
    this.outletRef.createEmbeddedView(this.contentRef);
}

完整的工作解决方案可以在这里找到https://stackblitz.com/edit/angular-component-rerender

于 2018-11-08T16:59:57.797 回答
5

ChangeDetectorRef.detectChanges()通常是这样做最集中的方式。ApplicationRef.tick()通常是一种大锤的方法。

要使用ChangeDetectorRef.detectChanges(),您需要在组件顶部使用它:

import {  ChangeDetectorRef } from '@angular/core';

...然后,通常当您将其注入构造函数中时,您通常会使用别名,如下所示:

constructor( private cdr: ChangeDetectorRef ) { ... }

然后,在适当的地方,你可以这样称呼它:

this.cdr.detectChanges();

打电话的地方ChangeDetectorRef.detectChanges()可能非常重要。您需要完全了解生命周期以及您的应用程序是如何运行和渲染其组件的。这里没有什么可以替代完全做你的功课并确保你完全理解 Angular 生命周期。然后,一旦你理解了这一点,你就可以ChangeDetectorRef.detectChanges()适当地使用(有时很容易理解你应该在哪里使用它,有时它可能非常复杂)。

于 2019-08-29T02:32:31.717 回答