简体   繁体   中英

Hover flickering when using immutability

I have a list of simple objects that I want to display, so I create components using *ngFor . Every component has css hover effect that changes its background. When I change object's property in an immutable way (create new array with replaced one object) the background of the associated component often flickers.

List component:

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);
  }
}

List item component:

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;
}

Here is a demo: https://stackblitz.com/edit/angular-pmdjqu?embed=1&file=app/listItem.component.ts

How can I fix this problem? Is Angular broken or am I doing something wrong? Maybe Angular is not designed for immutable manipulations?

(In React such problem does not exist: https://stackblitz.com/edit/react-bdul7z?file=index.js )

You provided key for react list.

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

But forgot to apply ngTrackBy option in angular

<list-item *ngFor="let item of items; trackBy: trackByFn"
                                      ^^^^^^^^^^^^^^^^^^

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

Angular Example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM