Angular NgRx ComponentStore 使用信号导致“不允许写入信号”错误

问题描述 投票:0回答:1

我正在转换为使用信号输入,并遇到了一个关于信号和 NgRx ComponentStore 的有趣问题。

组件商店:

interface State {
  user: any;
  isBusy: boolean;
}

@Injectable()
export class UserStore extends ComponentStore<State> {
  private readonly http = inject(HttpClient);
  readonly user = this.selectSignal((state) => state.user);
  readonly isBusy = this.selectSignal((state) => state.isBusy);

  private readonly updateUser = this.updater((state, user: any) => ({
    ...state,
    user,
    isBusy: false,
  }));

  readonly load = this.effect((id$: Observable<number>) =>
    id$.pipe(
      tap(() => this.patchState({ isBusy: true })), // Causes the signal write error
      switchMap((id: number) =>
        this.http
          .get<any>(`https://jsonplaceholder.typicode.com/users/${id}`)
          .pipe(
            tapResponse(
              (user) => this.updateUser(user), // Does not cause signal write error because it's after the http call
              () => this.patchState({ isBusy: false })
            )
          )
      )
    )
  );

  constructor() {
    super({
      user: null,
      isBusy: false,
    });
  }
}

成分:

@Component({
  selector: 'app-user',
  standalone: true,
  imports: [CommonModule],
  template: `<div>
  Is Busy: {{ isBusy() }}

  @if(!isBusy()) {
  <pre>{{ user() | json }}</pre>
  }
</div>`,
  styleUrl: './user.component.css',
  providers: [UserStore],
})
export class UserComponent {
  private readonly store = inject(UserStore);
  id = input.required<number>();
  user = this.store.user;
  isBusy = this.store.isBusy;

  constructor() {
    effect(
      () => {
        this.store.load(this.id());

        // Fixes error, but only works the first time the input is set
        // asapScheduler.schedule(() => this.store.load(this.id()));
      },
      {
        //allowSignalWrites: true, // Fixes issue, but is it the right way?
      }
    );
  }
}

我想对信号输入使用效果来触发加载数据,但是如果我在 http 调用之前修改任何状态,则会收到“写入信号”错误。这对我来说很有意义。 我知道它应该如何运作。然而,在这种情况下,是否最好只启用信号写入并称其为良好?或者应该重构整个事情以另一种方式完成这个任务?

此外,值得注意的是,我正在严格遵循推荐的方式来实现文档中的效果

我创建了一个 StackBlitz 来演示这个问题

angular signals ngrx ngrx-component-store
1个回答
0
投票

您可以尝试将信号转换为可观测值,然后再将其传递给您的

load
函数,如下所示:

@Component({
  selector: 'app-user',
  standalone: true,
  imports: [CommonModule],
  template: `<div>
  Is Busy: {{ isBusy() }}

  @if(!isBusy()) {
  <pre>{{ user() | json }}</pre>
  }
</div>`,
  styleUrl: './user.component.css',
  providers: [UserStore],
})
export class UserComponent {
  id = input.required<number>();
  user = this.store.user;
  isBusy = this.store.isBusy;

  private id$ = toObservable(this.id);
  private readonly store = inject(UserStore);

  constructor() {
    this.store.load(this.id$);
  }
}

如果没有组件构造函数的影响,错误应该消失。

© www.soinside.com 2019 - 2024. All rights reserved.