【问题标题】:How to not re-initialise child component when parent property changes?父属性更改时如何不重新初始化子组件?
【发布时间】:2019-08-16 16:42:42
【问题描述】:

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

  • 我使用为此目的提供的发布按钮中的按钮打开 cmets,它们正确加载
  • 我点击赞按钮,然后引发LikePost 动作
  • 然后触发LikePostSuccess 操作,将新的帖子对象(更新的点赞数)作为有效负载。然后更新点赞计数器。
  • 但问题是:当post.likesCount 属性被更新时,子CommentsComponent 被重新初始化(而内部没有数据发生变化)并且它使显示闪烁。

它是如何实现的以及到目前为止我尝试了什么:

  • 我使用@ngrx/entity 和两个不同的reducer 来管理帖子和评论。
  • 在PostsComponent,我设置changeDetection: ChangeDetectionStrategy.OnPush
  • 我注意到当状态以不可变的方式完全更改时会发生这种行为(通过使用adapter.UpdateOne() 方法),但如果我只是以可变的方式直接更改属性post.likesCount,它可以解决问题,但是这是一种不好的做法。
  • 我尝试在组件中显示此likesCount,并使用从为此目的(likesCount$(post) | async as likesCount)制作的选择器中获取的 Observable。然后我以为数据的引用不会动,不会有子初始化,但它不起作用。

posts.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>

cmets.component.html

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

posts.reducer.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);
  })

  // ...
);

posts.component.ts

// ...

comments$(post: Post): Observable<UserComment[]> {
  return this.store.pipe(select(selectCommentsByPostId(post.id)));
}

// ...

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

问题是否来自 ChangeDetection?从存储状态更新的方式(可变/不可变)?使用@ngrx/entity库是一个不错的选择吗?

感谢您的帮助

【问题讨论】:

  • 你能发布那个 cmets$(post) 函数吗
  • 你应该尝试trackBy 来避免创建元素 - netbasal.com/…
  • @user2216584 成功了!非常感谢!请将此评论添加为答案,我会将其标记为“已接受”

标签: angular ngrx


【解决方案1】:

正如我所见,您更新了帖子,然后进行了迭代,在该迭代中,您只需创建一个新的子组件,这就是您的子组件被重新初始化的原因。

【讨论】:

    【解决方案2】:

    解决方案是在 *ngFor 中使用trackBy 来强制 Angular 保持对象的相同引用,这样它就不需要重新初始化它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      相关资源
      最近更新 更多