You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中如何不刷新整页仅重新加载视图?

问题描述

我有一个父组件和两个子组件,其中add-friend子组件需要更新父组件的视图。我编写了receiveReloadFriendLists()方法,日志能正常输出,但视图始终不更新——当前应展示好友列表。我不想刷新页面,因为页面上有正在运行的动画,刷新会中断动画。怀疑是父组件存在遗漏或操作错误,查阅Stack Overflow相关回答后仍未解决问题。


父组件代码

@Component({
  selector: 'app-friends',
  templateUrl: './friends.component.html'
})
export class FriendsComponent implements OnInit {
  requested$: Observable<RelationResponse[]>;
  requested: RelationResponse[] = [];

  constructor(
    private store: Store,
    private router: Router,
    private appStore: Store<AppState>,
    private _fb: FormBuilder
  ) {
    this.requested$ = this.store.select(selectRequestedRelationResponse);
  }

  ngOnInit(): void {
    this.getRequestedRelations();
  }

  private getRequestedRelations() {
    this.store.dispatch(invokeFindRequestedRelations({
        userId: StorageUtil.getUserId(),
        relationStatusRequest: RelationStatusRequest.REQUESTED
      })
    );

    this.appStore.pipe(select(selectAppState)).subscribe((appState) => {
        if (ApiUtil.ifApiStatusIsSuccessReset(appState, this.appStore)) {
          this.requested$.subscribe((relationResponses) => {
            this.requested = relationResponses;
          })
        }
      }
    );
  }

  receiveReloadFriendLists() {
    console.log("reload");
    this.getRequestedRelations();
  }
}

父组件HTML

<app-add-friend (reloadRelationsEvent)="receiveReloadFriendLists()" class="p-0"></app-add-friend>

<app-relation-list class="p-0"
                   [show]=hasFriendRequests()
                   showHeadline="Friend requests"
                   noShowHeadline="No Friend requests"
                   [relations]="requested"
                   [enableAccept]="true"
                   [enableBlock]="true"
                   [enableDelete]="true"></app-relation-list>

子组件-添加好友

@Component({
  selector: 'app-add-friend',
  templateUrl: './add-friend.component.html'
})
export class AddFriendComponent {

  @Output() reloadRelationsEvent = new EventEmitter<void>();
  @ViewChild('sendFriendRequestCallout') sendFriendRequestCallout!: CalloutComponent;

  addFriendForm: FormGroup;

  constructor(private _fb: FormBuilder,
              private store: Store) {
    this.addFriendForm = this.createAddFriendForm();
  }

  public createAddFriendForm(): FormGroup {
    ...
  }

  sendFriendRequest() {
    ....
  }

  reloadFriendLists() {
    this.reloadRelationsEvent.emit();
  }
}

子组件-展示好友

@Component({
  selector: 'app-relation-list',
  templateUrl: './relation-list.component.html'
})
export class RelationListComponent {

  @Input() show: boolean = false;
  @Input() showHeadline: string = '';
  @Input() noShowHeadline: string = '';
  @Input() relations: RelationResponse[] = [];
  @Input() enableAccept: boolean = false;
  @Input() enableBlock: boolean = false;
  @Input() enableDelete: boolean = false;

...

}

子组件-展示好友HTML

<div class="card p-3 mt-3">
  <h5 class="card-title">{{ showHeadline }}</h5>

  <ng-container *ngFor="let relation of relations">
    {{relation.contactUsername }}
  </ng-container>
</div>

问题分析与解决方案

核心问题

  1. 嵌套订阅时机错误:当appStore返回成功状态时才去订阅requested$,但此时store.dispatch触发的状态更新可能已完成,新订阅无法捕获到最新数据。
  2. 重复订阅内存泄漏:每次调用getRequestedRelations都会新增订阅,导致内存泄漏和不可预期的赋值行为。
  3. 手动赋值可能未触发变更检测:即使requested更新,订阅时机错误也会导致视图无法同步。

方案1:使用Async管道(推荐)

直接用Angular的async管道绑定Observable,无需手动维护数组,自动处理订阅和变更检测。

修改父组件

@Component({
  selector: 'app-friends',
  templateUrl: './friends.component.html'
})
export class FriendsComponent implements OnInit {
  requested$: Observable<RelationResponse[]>;

  constructor(
    private store: Store,
    private router: Router,
    private appStore: Store<AppState>,
    private _fb: FormBuilder
  ) {
    this.requested$ = this.store.select(selectRequestedRelationResponse);
  }

  ngOnInit(): void {
    this.getRequestedRelations();
  }

  private getRequestedRelations() {
    this.store.dispatch(invokeFindRequestedRelations({
        userId: StorageUtil.getUserId(),
        relationStatusRequest: RelationStatusRequest.REQUESTED
      })
    );
    // 移除嵌套订阅,API状态处理可单独在effect或其他逻辑中完成
  }

  receiveReloadFriendLists() {
    console.log("reload");
    this.getRequestedRelations();
  }
}

修改父组件HTML

将[relations]="requested"替换为[relations]="requested$ | async":

<app-add-friend (reloadRelationsEvent)="receiveReloadFriendLists()" class="p-0"></app-add-friend>

<app-relation-list class="p-0"
                   [show]=hasFriendRequests()
                   showHeadline="Friend requests"
                   noShowHeadline="No Friend requests"
                   [relations]="requested$ | async"
                   [enableAccept]="true"
                   [enableBlock]="true"
                   [enableDelete]="true"></app-relation-list>

方案2:修复手动订阅逻辑

若坚持手动维护数组,需正确管理订阅,避免嵌套和泄漏:

import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators';

@Component({
  selector: 'app-friends',
  templateUrl: './friends.component.html'
})
export class FriendsComponent implements OnInit, OnDestroy {
  requested$: Observable<RelationResponse[]>;
  requested: RelationResponse[] = [];
  private destroy$ = new Subject<void>();

  constructor(
    private store: Store,
    private router: Router,
    private appStore: Store<AppState>,
    private _fb: FormBuilder
  ) {
    this.requested$ = this.store.select(selectRequestedRelationResponse);
  }

  ngOnInit(): void {
    // 提前订阅requested$,持续监听数据变化
    this.requested$.pipe(takeUntil(this.destroy$)).subscribe((relationResponses) => {
      this.requested = relationResponses;
    });

    this.getRequestedRelations();
  }

  private getRequestedRelations() {
    this.store.dispatch(invokeFindRequestedRelations({
        userId: StorageUtil.getUserId(),
        relationStatusRequest: RelationStatusRequest.REQUESTED
      })
    );

    // 单独处理API状态,只取一次成功状态后取消订阅
    this.appStore.pipe(
      select(selectAppState),
      takeUntil(this.destroy$),
      take(1)
    ).subscribe((appState) => {
      ApiUtil.ifApiStatusIsSuccessReset(appState, this.appStore);
    });
  }

  receiveReloadFriendLists() {
    console.log("reload");
    this.getRequestedRelations();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

额外检查项

  • 确认selectRequestedRelationResponse选择器能正确返回更新后的store状态;
  • 检查ApiUtil.ifApiStatusIsSuccessReset方法是否影响了store状态的正常更新。

内容的提问来源于stack exchange,提问作者Bianca

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:54:56