使用不变性时悬停闪烁

时间:2018-03-12 15:59:07

标签: javascript angular immutability angular5

我有一个我想要显示的简单对象列表,因此我使用*ngFor创建组件。每个组件都有css悬停效果,可以改变其背景。当我以不可变的方式更改对象的属性(使用替换的一个对象创建新数组)时,关联组件的背景经常会闪烁。

列表组件:

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

@Component({
  selector: 'my-app',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <list-item *ngFor="let item of items"
      [item]="item"
      (toggle)="onToggle(item)"
    ></list-item>
  `,
})
export class AppComponent  {
  items = [
    { name: 'item1', toggled: false },
    { name: 'item2 ', toggled: true },
    { name: 'item3', toggled: false }
  ];

  onToggle(item) {
    const updatedItem = {
      ...item,
      toggled: !item.toggled
    };

    this.items = this.items.map(item => item.name === updatedItem.name ? updatedItem : item);
  }
}

列出项目组件:

import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'list-item',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <div class="container">
      <span>{{ item.name }}: {{ item.toggled }}</span>
      <button (click)="toggle.emit()">Toggle!</button>
    </div>
  `,
  styles: [`
    .container {
      width: 400px;
      height: 50px;
      border: 1px solid black;
      display: flex;
      padding: 20px;
      justify-content: space-between;
      align-items: center;
    }

    .container:hover {
      background-color: yellow;
    }
  `]
})
export class ListItemComponent {
  @Input() item: Item;
  @Output() toggle: EventEmitter<void> = new EventEmitter<void>();
}

export interface Item {
  name: string;
  toggled: boolean;
}

以下是演示:https://stackblitz.com/edit/angular-pmdjqu?embed=1&file=app/listItem.component.ts

如何解决此问题? Angular被破坏了还是我做错了什么? 也许Angular不是为不可变的操作而设计的?

(在React中这样的问题不存在:https://stackblitz.com/edit/react-bdul7z?file=index.js

1 个答案:

答案 0 :(得分:2)

您为反应列表提供了key

<ListItem key={item.name}
          ^^^^^^^^^^^^^^^

但忘了在角色

中应用ngTrackBy选项
<list-item *ngFor="let item of items; trackBy: trackByFn"
                                      ^^^^^^^^^^^^^^^^^^

trackByFn(i, x) {
  return x.name;
}

<强> Angular Example