父属性更改时如何不重新初始化子组件?

时间:2019-08-16 16:42:42

标签: angular ngrx

我正在开发一个具有Facebook之类的墙的应用程序,其中包含帖子组件(具有点赞的计数器)和嵌套评论组件,这些组件按需通过帖子内的按钮加载。我正在使用NgRx商店,并且按照以下步骤操作时会出现意外行为:

  • 我为此目的在发布按钮中使用按钮打开评论,它们已正确加载
  • 我单击“赞”按钮,然后引发number动作
  • 然后触发一个LikePost动作,并使用新的post对象(已更新点赞的次数)作为有效负载。然后更新点赞计数器。
  • 但是问题是:更新LikePostSuccess属性后,子post.likesCount会重新初始化(而内部的数据没有更改),这会使显示闪烁。

它的实现方式以及到目前为止我尝试过的工作:

  • 我正在使用CommentsComponent和两个不同的reducer来管理帖子和评论。
  • @ngrx/entity中,我设置了PostsComponent
  • 我注意到,当状态以不可变的方式完全更改(通过使用changeDetection: ChangeDetectionStrategy.OnPush方法)时会发生这种行为,但是如果我只是以可变的方式直接更改属性adapter.UpdateOne(),则可以解决问题,但这是一个坏习惯。
  • 我试图通过从用于此目的的选择器(post.likesCount)获得的Observable在组件中显示此likesCount。然后,我认为对数据的引用将不会移动,并且不会进行子级初始化,但是它不起作用。

posts.component.html

likesCount$(post) | async as likesCount

comments.component.html

<ng-container *ngFor="let post of posts">
    <div>{{ post.title }}</div>

    <button (click)="likePost(post)">
        <mat-icon>thumb_up</mat-icon>
        <span>{{ post.likesCount }}</span>
    </button>

    <button (click)="toggleComments(post)">
        <mat-icon>chat_bubble</mat-icon>
    </button>

    <div>
        <ng-container *ngIf="comments$(post) | async as comments">
            <app-comments [comments]="comments" [postId]="post.id"></app-comments>
        </ng-container>
    </div>
</ng-container>

posts.reducer.ts

<ul>
    <li *ngFor="let comment of comments">{{ comment.content }}</li>
</ul>

posts.component.ts

const reducer = createReducer(
  initialState,

  // ...

  on(postsActions.likePostSuccess, (state, props) => {
    const update: Update<Post> = {
      id: props.post.id,
      changes: {
        likesCount: props.post.likesCount
      }
    };
    return postsAdapter.updateOne(update, state);
  })

  // ...
);

最后,问题是:如何在不触发子级初始化的情况下更新父级组件属性?这里的问题是孤立的,但是我无法想象如果我有很多嵌套的组件会发生什么。

问题是否来自ChangeDetection?从商店状态更新的方式(可变/不可变)?使用// ... comments$(post: Post): Observable<UserComment[]> { return this.store.pipe(select(selectCommentsByPostId(post.id))); } // ... 库是不错的选择吗?

谢谢您的帮助

2 个答案:

答案 0 :(得分:0)

正如我所见,您更新了帖子,然后对其进行迭代,然后在该迭代中,您仅创建了一个新的子组件,这就是为什么要重新初始化子组件的原因。

答案 1 :(得分:0)

解决方案是在* ngFor中使用trackBy,以强制Angular保持对象的相同引用,从而无需重新初始化它。