我正在转换为使用信号输入,并遇到了一个关于信号和 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 调用之前修改任何状态,则会收到“写入信号”错误。这对我来说很有意义。 我知道它应该如何运作。然而,在这种情况下,是否最好只启用信号写入并称其为良好?或者应该重构整个事情以另一种方式完成这个任务?
此外,值得注意的是,我正在严格遵循推荐的方式来实现文档中的效果。
您可以尝试将信号转换为可观测值,然后再将其传递给您的
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$);
}
}
如果没有组件构造函数的影响,错误应该消失。