同一商店在多个组件上

时间:2019-10-31 07:55:15

标签: angular ngrx-store

在我的应用中,我有user.componentcollege.component。 在user.componentstore中,我得到了用户列表

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,我会吸引用户,但是当我进入大学页面后, 我收到错误消息

  

无法读取未定义的属性“数据”   为用户。

在这种情况下处理这种存储的最佳方法是什么?

检查数据是否在存储和调用分派中存在,或对每个组件的loadUsers()采取相同的动作/减少器/效果?

Thnx

2 个答案:

答案 0 :(得分:2)

如果您的用户数据变化很大,则可以重新加载。如果您的用户数据通常是静态的,那么多次调用是不明智的,因为这只会无缘无故地使您的应用变慢。

要解决单个加载问题,有两种方法。您应该在实体上保留一个已加载的参数,然后在成功加载时将化简器中的已加载值设为true。

您现在可以订阅该已加载的值,如果它为false,则分派负载,如果为true,则不分派调用。这种方法使效果更简单,但是您的容器将具有更长/更丑陋的代码。

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

  1. 组件加载并订阅可能或将要存储数据的存储变量。
  2. 在ngOnInit上分派操作以加载数据。
  3. 在效果检查中,商店是否有数据,并且可能是否早于特定时间。我尽力只检查尽可能少的有效存储,因为这会使它们变得更复杂,但是在实际项目中,我通常会有6-12种这样的效果。
  4. 如果没有数据或过时的调用http进行加载,但是如果已经加载,那么我将分派一个类似{type:'entityXLoadedFromStore'};的操作。除了将日志消息添加到系统中以查看它是否已从商店中加载外,它什么都不会做。

这种方法可以使您的代码在容器中更整洁,但会使效果复杂化。

两条路线均可行,您可以选择自己喜欢的路线。

我也想参考NGRX团队提供的fantastic demo应用程序,这是ngrx方法的灵感之源。 (但是他们没有在那里解决您的问题)。

答案 1 :(得分:0)

如果您对同一个实体两次执行API调用,使用存储的目的是什么?

据我说,您不应两次调用用户API。您应尽量减少API调用,以向客户提供非常轻松和高效的用户体验。

为此,我建议您在状态中添加loadedloading两个新字段,然后创建一个选择器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仅在未加载用户时被调用一次,并且在加载后每次都会从商店本身返回用户。

注意-

  • 最初加载加载将为假。
  • 如果要从前端编辑用户,请确保也更新商店中的用户。
  • 在您的 LoadUsers操作中,确保将用户的 loading 状态更改为true
  • 在您的 API响应中,确保将用户的已加载状态更改为true,并将已加载状态更改为false