【问题标题】:Issue with clearing state from an ngrx/redux store when the user logs out用户注销时从 ngrx/redux 存储中清除状态的问题
【发布时间】:2017-04-20 03:48:08
【问题描述】:

我的应用程序使用 ngrx/rxjs。我依靠 ngrx 效果从商店中注销和清除状态。

不幸的是,因为我的一个组件通过选择器订阅了商店(见下文:getLatestMessagesByCounterParty),并且因为在该组件被销毁之前清除了状态,所以我收到以下错误:

错误类型错误:无法读取 null 的属性“id” 在 getCurrentUserAccountId 处

...表示currentUserAccountnull,这很符合逻辑,因为我刚刚从商店中清除了状态。

这里是signout$ 效果:

  @Effect()
  signout$: Observable<Action> = this.actions$
    .ofType(authenticated.ActionTypes.SIGNOUT)
    .switchMap(() =>
      this.sessionSignoutService.signout()
        .do(() => {
          localStorage.removeItem('authenticated');
          localStorage.removeItem('sessionToken');
        })
        .concatMap(() => [
          new ClearMessagesAction(null),
          new ClearUserAccountAction(null),//Error thrown here...
          go(['/signin'])//Never reached...
        ]));

这里是订阅登录状态的组件:

  ngOnInit() {
    this.store.select(fromRoot.getLatestMessagesByCounterParty)
      .subscribe(latestMessages => this.latestMessages = this.messageService.sortMessagesByDate(latestMessages, this.numberOfConversations));
  }

以及相关的选择器:

...
const getCurrentUserAccountId = (state: State) => state.userAccount.currentUserAccount.id;
const getMessagesState = (state: State) => state.message.messages;

...
export const getLatestMessagesByCounterParty = createSelector(getCurrentUserAccountId, getMessagesState, fromMessage.latestMessagesByCounterParty);

我正在寻找关于何时、何地以及如何从商店中清除状态的最佳做法。理想情况下,我希望在订阅组件被销毁的最后时间这样做。

有人可以建议吗?

编辑:让我进一步完善我的评论。我上面的代码应该如下所示。

   .concatMap(() => [
      new ClearMessagesAction(null),
      new ClearUserAccountAction(null),//Error thrown right after this action because selector cannot find id variable on state
      go(['/signin'])//Never reached...
    ]));

【问题讨论】:

  • 听起来你需要在某处添加filter(account =&gt; !!acount)
  • 你好 Cgatian。感谢您的回复。我想知道是否没有比添加过滤器更好的做法......
  • 你好 Cgatian:你能提供一个关于如何在选择器上添加过滤器的例子吗?

标签: ngrx reselect ngrx-effects


【解决方案1】:

正如@cgatian 所说,您可能会使用过滤器。但这就是使用该代码在幕后会发生的事情:

.concatMap(() => [
  new ClearMessagesAction(null),
  new ClearUserAccountAction(null),//Error thrown here...
  go(['/signin'])//Never reached...
]));

你首先要发送一个动作ClearMessagesAction(null)
然后该操作将由您的减速器处理。
___将产生一个新的状态
___您的选择器将在
之后立即触发 ___会发生错误,因为您最终会得到不一致的存储(正如您所期望的那样,另一个操作 ClearUserAccountAction(null) 在选择器启动之前同时调度

为避免状态不一致,您应该采取的措施是:
- 创建您在两个减速器中处理的 一个 操作。这样,您的减速器都将被修改,只有这样,选择器才会启动
- 使用允许您将多个操作作为一个分派的库(如redux-batched-actions)。这样你就可以写出这样的东西:

batchActions([
  new ClearMessagesAction(null), --> selectors not triggered yet
  new ClearUserAccountAction(null) --> selectors not triggered yet
]); --> selectors triggered now

【讨论】:

  • 谢谢马克西姆。你能提供一个样本过滤器吗?过滤器应该进入选择器吗?
  • 当然。不要将选择器传递给this.store.select,而是使用let 运算符。它允许您获得整个 observable。这是example。然后只需拨打this.store.let(yourSelector)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-09
  • 1970-01-01
  • 1970-01-01
  • 2020-08-03
相关资源
最近更新 更多