【问题标题】:ngFor and trackBy with async data from API still re-rendering DOM?ngFor 和 trackBy 与来自 API 的异步数据仍然重新渲染 DOM?
【发布时间】:2019-10-28 11:01:23
【问题描述】:

我想将ngForasync 数据(从API 加载)和trackBy 一起使用以提高性能并更新列表,而不会在数据更新时出现DOM 闪烁/闪烁。

如果数据是静态的 - 一切正常。但是当我尝试使用从 API 加载的数据时 - trackBy 不起作用。

直播

来自 API:https://stackblitz.com/edit/angular-hx4p39
静态数据:https://stackblitz.com/edit/angular-myb6vj

组件

export class AppComponent {

  constructor(private http: HttpClient){}

  comments$: Observable<Comment[]> = this.http.get<Comment[]>(`https://jsonplaceholder.typicode.com/comments?_start=0&_limit=5`);

  add() {
    this.comments$ = this.http.get<Comment[]>(`https://jsonplaceholder.typicode.com/comments?_start=0&_limit=6`);
  }

  edit() {
    this.comments$ = this.comments$.pipe(
      map(comments => {
        comments.map( comment => {
          if(comment.id === 5){ comment.name = 'edit'; }
          return comment;
        });
        return comments;
      })
    );
  }

  itemTrackBy(index: number, item: Comment) {
    return item.id;
  }
}

interface Comment {
  postId;
  id;
  email;
  name;
  body;
}

模板

<button (click)="add()">Make 6</button>
OR
<button (click)="edit()">edit 5-th element</button>

<ul>
  <li *ngFor="let comment of (comments$ | async); trackBy: itemTrackBy">
    {{comment.id}} - {{comment.name}}
  </li>
</ul>

【问题讨论】:

    标签: javascript angular rxjs ngfor


    【解决方案1】:

    发生这种情况是因为您将 observable 更改为另一个 observable 实例。 ngFor 检测到 在设置新的 observable 时重新渲染 dom。正确的工作方式是不设置新的 observable,只是在 observable 上推送新项目

    这是一个应用这种方法的 stackblitz 示例,您会看到 dom 没有重新渲染:https://stackblitz.com/edit/angular-wslaz7

    我不知道为什么带有静态数据的示例不会重新渲染 dom,这可能是整个操作为“同步”时的副作用,因为如果我在 of( ) 喜欢:

    this.episodes =  of([
          {id: 1, name: "name1"},
          {id: 2, name: "name2"}
        ]).pipe(delay(100));
    

    你会看到它会重新渲染项目。

    我们可以问 Angular 团队,为什么在没有应用 delay() 时它不重新渲染,我不知道。

    希望这会有所帮助!

    【讨论】:

    • 非常感谢您的帮助!我发现您的代码无需设置新的 changeDetection 策略即可正常工作。这种情况下有必要吗?
    • 我很高兴它有帮助:)。您的意思是使用 onPush 还是 Default 更改检测策略?在此示例中,没有输入,因此两种策略都会给出相同的结果。虽然,默认情况下在所有组件上使用 onPush 是一种很好的做法。
    猜你喜欢
    • 2017-03-04
    • 2020-01-15
    • 2019-02-03
    • 1970-01-01
    • 2018-11-18
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 2017-12-01
    相关资源
    最近更新 更多