我已经习惯了传统的 Ng/Rx,现在正在深入研究 Signals 和 Ng/Rx SignalStore。
我知道通过 SignalStore,我们可以提供 withMethods。 然后,我们可以从注入商店的组件中调用商店上的这些方法。
假设我有一个书店和一个用户商店。 用户存储存储当前登录的用户。基本上只有当用户登录/退出时它才会改变。 书店存储书籍列表,并有一个方法为当前用户加载书籍。
下面的代码是如何设置的? 在传统的 Ng/Rx 中,我们会有一个效果,对操作做出反应,然后从用户状态获取最新值,执行请求,然后调度另一个操作。在 bookStore 中提到 userStore 对我来说感觉像是代码味道。
const BooksStore = signalStore(
withState(initialState),
withMethods((store) => (
const httpClient = inject(HttpClient);
const userStore = inject(UserStore);
return loadBooksForLoggedInUser(): void {
httpClient.get<TalkData>(`/books?userId=${userStore.id()}`)
// use the result and patch state etc. etc.
}
))
P.s.上面的代码可能并不完美,因为我只是将其写在 stackoverflow 中以表达我的问题。目前我没有任何实际代码可以分享,因为我的问题是假设的。我已经搜索过了,但我找不到任何遇到过这种情况的人,但这感觉很奇怪......因为感觉这应该是相当普遍的。
我不认为在另一家商店的
withMethods
中使用一个商店是一种代码味道,事实上,我认为这是针对有 2 个具有不同范围的商店的情况的预期架构。 (在您的情况下,很明显用户商店的寿命比书店更长或相同)。
我同意你应该使用一个效果,这样每当用户ID改变时,你就会为当前用户重新加载书籍。我还认为你应该使用 rxMethod 因为 api 是异步的。
withMethods(store => {
const http = inject(HttpClient);
return {
loadBooksForCurrentUser: rxMethod<number>(id$ => id$.pipe(
tap(/* empty the talk data, set "busy" to true... */),
switchMap(id => httpClient.get<TalkData>(/* the url*/)),
tap(talkData => // use the result and patch state //)
))
}
}),
withHooks(store => {
const userStore = inject(UserStore);
return {
onInit() {
// note - we pass the id signal by reference!!!.
// rxMethod subscribes to it so it is called again
// whenever it changes
store.loadBooksForCurrentUser(userStore.id);
}
}
})