【问题标题】:How using changeDetection: ChangeDetectionStrategy.OnPush in angular2如何使用 changeDetection: ChangeDetectionStrategy.OnPush in angular2
【发布时间】:2016-07-22 08:40:19
【问题描述】:

我有简单的 angular2 应用程序。该应用程序只有一个具有 ChangeDetectionStrategy.OnPush 的组件。 问题是组件永远不会刷新它的视图。 数据数组更新后如何让组件自行刷新? 这里是代码。我正在使用 Angular 2.0.0-rc.4。

index.html

<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">

<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
  System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<app style="width:100%;height:100%;">Loading...</app>
</body>

main.ts

import { bootstrap }    from "@angular/platform-browser-dynamic";
import { AppComponent } from "./app";
bootstrap(AppComponent);

app.ts

import {Component, ComponentRef, ComponentFactory, ViewContainerRef} from "@angular/core";
import {ListComponent} from "./list";

@Component({
    selector: "app",
    template: `
    <div>
      <h1>Angular2 - app</h1>
      <gm-list></gm-list>
    </div>
    `,
    directives: [ListComponent]
})
export class AppComponent {
}

list.ts

import {Component, Input, NgZone, ChangeDetectionStrategy, ChangeDetectorRef} from "@angular/core";

@Component({
    selector: "gm-list",
    template: `<div style='width:100%;height:100%;'>
    List
    <div *ngFor="let item of data" >
        <div>
            {{ test }}
        </div>
        <div>
            <label class="checkbox">
                <input type="checkbox" [(ngModel)]="item.visible"> {{ item.name }}
            </label>
        </div>
        </div>
    </div>`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListComponent {
    private _data: any = [];

    constructor(private zone: NgZone, private changeDetectorRef: ChangeDetectorRef) {
    }

    ngOnInit(): void {
        var me = this;
        setTimeout(function () {
            me.data = [
                { id: 1, name: "one", visible: true },
                { id: 2, name: "two", visible: false },
                { id: 3, name: "three", visible: true },
                { id: 4, name: "four", visible: false },
                { id: 5, name: "five", visible: true },
                { id: 6, name: "six", visible: true }
            ];
        }, 3000);
    }

    @Input() set data(data: any) {
        this._data = data;
        console.log("databind");
    }

    get data(): any {
        return this._data;
    }

    get test(): string {
        //console.log("test");
        return "test";
    }
}

【问题讨论】:

    标签: angular


    【解决方案1】:

    来自https://github.com/angular/angular/issues/4746#issuecomment-150754049

    OnPush 只会在输入属性具有 由于更改检测检查而被更改

    1) 所以您需要通过changeDetectorRef.markForCheck 手动运行更改,例如:

    export class ListComponent {
        constructor(private changeDetectorRef: ChangeDetectorRef) {}
    
        ngOnInit(): void {
            setTimeout(() => {
                this.data = [...];
                this.changeDetectorRef.markForCheck();
            }, 3000);
        }
        ...
    

    demo plunker

    2) 如果您更改父项上的输入数据,它将被更新,因为这将触发对子项的检查 (plunker):

    @Component({
      selector: 'my-app',
      template: `<gm-list [data]="data"></gm-list>`,
      directives: [ListComponent]
    })
    export class App {
      data:any[];
      constructor() {
         setTimeout(() => {
            this.data = [...];
        }, 3000);
      }
    }
    

    3) 或者您可以使用对父组件的引用(或使用EventEmitter)来运行更新,如下所示:

    export class ListComponent {
        constructor(@Inject(forwardRef(() => App)) private parent:App) {}
    
        ngOnInit(): void {
          setTimeout(() => {
              this.parent.data = [...];
          }, 3000);
        }
    }  
    
    @Component({
      selector: 'my-app',
      template: `<gm-list [data]="data"></gm-list>`,
      directives: [ListComponent]
    })
    export class App {
      data: any[];
    }
    

    plunker

    【讨论】:

      【解决方案2】:

      Angular2 还不稳定。并且代码可能会在版本中更改。找到以下解决方案,适用于 rc4 版本。

      1) 添加

      changeDetection: ChangeDetectionStrategy.OnPush,
      

      2) 组件状态改变后调用

      this.changeDetectorRef.markForCheck();
      this.changeDetectorRef.detectChanges();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-21
        相关资源
        最近更新 更多