多个组件上的同一商店
Same store on multiple component
在我的应用程序中,我有 user.component
和 college.component
。
在 user.component
和 store
中,我得到用户列表
this.store.dispatch(new LoadUsers());
this.users$ = this.store.select(UserSelector.getAllUsers)
this.users$.subscribe(...)
并且在 college.component
我也需要来自商店的这个用户,我调用相同的调度
this.store.dispatch(new LoadUsers());
this.users$ = this.store.select(UserSelector.getAllUsers)
this.users$.subscribe(...)
我调用相同的 this.store.dispatch(new LoadUsers());
因为,如果我在第一页加载打开的大学页面,我的商店中没有用户,我需要调用他们。
如果我第一次打开 users.component
我会得到用户,但是当我进入大学页面后
我收到错误
Cannot read property 'data' of undefined
for users.
在这种情况下处理这样的商店的最佳方式是什么?
检查存储中是否存在数据并调用 dispatch 或为每个组件为 loadUsers()
制作相同的 action/reducer/effect?
谢谢
如果您对同一实体进行两次 API 调用,那么使用商店有什么意义?
根据我的说法,你不应该给用户 API 打电话两次。您应该尽可能减少 API 次调用,以便为客户提供非常轻便和高效的用户体验。
为此,我建议在您所在的州添加 loaded
和 loading
两个新字段,然后像这样创建一个选择器 isInitialised
:
export const getUsersInitialised = (state: State) => state.loaded || state.loading;
然后仅当用户未加载或任何其他组件已像这样加载用户时才加载用户,
getUsers(): Observable<User[]> {
const users = this.store.select(getAllUsers);
this.store.select(getUsersInitialised).pipe(take(1), filter(v => !v)).subscribe(() => {
this.store.dispatch(new LoadUsers());
});
return users;
}
这样,用户 API 只会在用户未加载时调用一次,一旦加载,每次用户都会从商店本身返回。
注意 -
- 最初 loading 和 loaded 将为 false。
- 如果您从前端编辑用户,请确保也更新商店中的用户。
- 在您的 LoadUsers 操作 中,确保将用户的 loading 状态更改为
true
- 在您的 API 响应 中,确保将用户的 loaded 状态更改为
true
并且加载状态 false
.
如果您的用户数据变化较大,重新加载即可。如果您的用户数据非常静态(通常情况下是这样),那么多次进行该调用是不明智的,因为它只会无缘无故地让您的应用变慢。
要解决单一加载问题,有两种方法。你应该在你的实体上保存一个加载的参数,然后在加载成功时将该加载的值在 reducer 中设置为 true。
您现在可以订阅该加载的值,如果它是 false,则分派负载,如果是 true,则不分派调用。此路线使效果更简单,但您的容器将具有 longer/uglier 代码。
constructor(private store: Store<fromAuth.State & fromData.State>){
this.users$ = this.store.select(UserSelector.getAllUsers);
}
ngOnInit() {
this.store.select(UserSelector.getUsersLoaded).subscribe(value =>
if (!value) this.store.dispatch(new LoadUsers());
);
}
一个更顺畅的方法是保持你的代码不变,然后检查效果。 (Duncan Hunter 在 ngrx 的 Pluralsights 课程上回复我) (ref. to ngrx course on pluralsight)
- 组件加载并订阅数据可能或将会存在的存储变量。
- 在 ngOnInit 上调度操作以加载数据。
- 在效果中检查存储是否有数据,也许它是否早于特定时间。我尽量只检查 store in effect 尽可能少,因为这会使它们变得更复杂,但在实际项目中,我经常有 6-12 个这样的效果。
- 如果没有数据或过时调用 http 来加载,但如果它已经加载,我将发送一个类似 {type: 'entityXLoadedFromStore'} 的操作;除了在系统中添加一条日志消息以便能够看到它是从商店加载的之外,它什么都不做。
这条路线使您的代码在容器中更清晰,但使效果变得复杂。
两条路线都可行,你可以选择你喜欢的。
我还想参考 NGRX 团队提供的 fantastic demo 应用程序,它是 ngrx 方法的重要灵感来源。 (但是他们没有在那里解决您的问题)。
在我的应用程序中,我有 user.component
和 college.component
。
在 user.component
和 store
中,我得到用户列表
this.store.dispatch(new LoadUsers());
this.users$ = this.store.select(UserSelector.getAllUsers)
this.users$.subscribe(...)
并且在 college.component
我也需要来自商店的这个用户,我调用相同的调度
this.store.dispatch(new LoadUsers());
this.users$ = this.store.select(UserSelector.getAllUsers)
this.users$.subscribe(...)
我调用相同的 this.store.dispatch(new LoadUsers());
因为,如果我在第一页加载打开的大学页面,我的商店中没有用户,我需要调用他们。
如果我第一次打开 users.component
我会得到用户,但是当我进入大学页面后
我收到错误
Cannot read property 'data' of undefined for users.
在这种情况下处理这样的商店的最佳方式是什么?
检查存储中是否存在数据并调用 dispatch 或为每个组件为 loadUsers()
制作相同的 action/reducer/effect?
谢谢
如果您对同一实体进行两次 API 调用,那么使用商店有什么意义?
根据我的说法,你不应该给用户 API 打电话两次。您应该尽可能减少 API 次调用,以便为客户提供非常轻便和高效的用户体验。
为此,我建议在您所在的州添加 loaded
和 loading
两个新字段,然后像这样创建一个选择器 isInitialised
:
export const getUsersInitialised = (state: State) => state.loaded || state.loading;
然后仅当用户未加载或任何其他组件已像这样加载用户时才加载用户,
getUsers(): Observable<User[]> {
const users = this.store.select(getAllUsers);
this.store.select(getUsersInitialised).pipe(take(1), filter(v => !v)).subscribe(() => {
this.store.dispatch(new LoadUsers());
});
return users;
}
这样,用户 API 只会在用户未加载时调用一次,一旦加载,每次用户都会从商店本身返回。
注意 -
- 最初 loading 和 loaded 将为 false。
- 如果您从前端编辑用户,请确保也更新商店中的用户。
- 在您的 LoadUsers 操作 中,确保将用户的 loading 状态更改为
true
- 在您的 API 响应 中,确保将用户的 loaded 状态更改为
true
并且加载状态false
.
如果您的用户数据变化较大,重新加载即可。如果您的用户数据非常静态(通常情况下是这样),那么多次进行该调用是不明智的,因为它只会无缘无故地让您的应用变慢。
要解决单一加载问题,有两种方法。你应该在你的实体上保存一个加载的参数,然后在加载成功时将该加载的值在 reducer 中设置为 true。
您现在可以订阅该加载的值,如果它是 false,则分派负载,如果是 true,则不分派调用。此路线使效果更简单,但您的容器将具有 longer/uglier 代码。
constructor(private store: Store<fromAuth.State & fromData.State>){
this.users$ = this.store.select(UserSelector.getAllUsers);
}
ngOnInit() {
this.store.select(UserSelector.getUsersLoaded).subscribe(value =>
if (!value) this.store.dispatch(new LoadUsers());
);
}
一个更顺畅的方法是保持你的代码不变,然后检查效果。 (Duncan Hunter 在 ngrx 的 Pluralsights 课程上回复我) (ref. to ngrx course on pluralsight)
- 组件加载并订阅数据可能或将会存在的存储变量。
- 在 ngOnInit 上调度操作以加载数据。
- 在效果中检查存储是否有数据,也许它是否早于特定时间。我尽量只检查 store in effect 尽可能少,因为这会使它们变得更复杂,但在实际项目中,我经常有 6-12 个这样的效果。
- 如果没有数据或过时调用 http 来加载,但如果它已经加载,我将发送一个类似 {type: 'entityXLoadedFromStore'} 的操作;除了在系统中添加一条日志消息以便能够看到它是从商店加载的之外,它什么都不做。
这条路线使您的代码在容器中更清晰,但使效果变得复杂。
两条路线都可行,你可以选择你喜欢的。
我还想参考 NGRX 团队提供的 fantastic demo 应用程序,它是 ngrx 方法的重要灵感来源。 (但是他们没有在那里解决您的问题)。