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

RxJS中更新Session对象Players数组失败,求正确实现方案

问题描述

我开发了一个简易应用,支持用户创建会话、加入会话并为该会话创建用户名。当前在新用户加入会话时,更新「players(用户)」数据遇到问题。

我的思路是使用一个session可观察对象来检测变化,并将变化传递给子组件以更新UI:

相关代码

app.component.html

<app-join-session></app-join-session>
<ng-container *ngIf="session$ | async as session">
  <app-current-players [session]="session"></app-current-players>
  <app-new-user [session]="session"></app-new-user>
</ng-container>

session.service.ts

export class SessionService {
  private subject = new ReplaySubject<Session>();
  public session$ = this.subject.asObservable();

  public setSession(session: Session) {
    this.subject.next(session)
  }

  public addUserToSession(session: Session): void {
    this.subject.next(session)
  }
}

app.component.ts

protected session$ = this.sessionService.session$;

new-user.component.ts

public createUserName(userName: FormControl): void {
  this.apollo.mutate<CreateUser>({
    mutation: userOperations.CREATE_USER,
    variables: {
      name: userName.value,
      sessionId: this.session.id,
    }
  })
  .subscribe({
    next: ({data}) => {
      this.session.players.push(data!.createUser)
      this.sessionService.addUserToSession(this.session)
    },
    error: (e: GraphQLError) => {
      this.errorMessage = {...e}.message;
    }
  })
}

我原本计划将创建的用户推入session的players数组,再通过subject.next传递以更新可观察对象,但此方法无效,还出现错误:

Cannot add property 19, object is not extensible at Array.push ()

请问有没有更优的方法来更新包含新玩家的session数据流?


解决方案

1. 解决对象不可扩展问题

出现object is not extensible错误,是因为从异步流或Apollo返回的session对象被冻结(不可扩展),无法直接修改原对象。需要创建会话对象的新副本,再添加新用户。

2. 修正组件内的更新逻辑

修改new-user.component.ts中的代码,通过创建新对象来更新会话数据:

public createUserName(userName: FormControl): void {
  this.apollo.mutate<CreateUser>({
    mutation: userOperations.CREATE_USER,
    variables: {
      name: userName.value,
      sessionId: this.session.id,
    }
  })
  .subscribe({
    next: ({data}) => {
      // 创建新的session副本,合并原数据与新玩家数组
      const updatedSession = {
        ...this.session,
        players: [...this.session.players, data!.createUser]
      };
      this.sessionService.addUserToSession(updatedSession);
    },
    error: (e: GraphQLError) => {
      this.errorMessage = {...e}.message;
    }
  })
}

3. 封装更新逻辑到Service(可选优化)

把创建新会话对象的逻辑移到Service中,让组件代码更简洁:

// session.service.ts
public addUserToSession(existingSession: Session, newUser: User): void {
  const updatedSession = {
    ...existingSession,
    players: [...existingSession.players, newUser]
  };
  this.subject.next(updatedSession);
}

组件中调用时只需传入原会话和新用户:

// new-user.component.ts
this.sessionService.addUserToSession(this.session, data!.createUser);

4. 原方法无效的核心原因

  • 原会话对象被冻结,无法直接修改其players数组
  • 即使对象可扩展,直接修改原对象后传递给next,由于对象引用未变,Angular变更检测可能不会触发UI更新;创建新对象能确保可观察流发出全新值,触发所有订阅者更新UI。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 17:18:21