使用 NGXS 订阅操作流的更简洁方式

Posted

技术标签:

【中文标题】使用 NGXS 订阅操作流的更简洁方式【英文标题】:Cleaner way of subscribing to the actions stream with NGXS 【发布时间】:2019-04-02 12:34:18 【问题描述】:

所以我通常有一个在点击时调度操作的方法:

create() 
  this.store.dispatch(new Create(this.form.value)); 

此代码触发以下场景并根据请求是否失败分派 CreateSuccess 或 CreateFailed

@Action(Create)
create( dispatch : StateContext<StateInterface>,  entity: Create) 
  return this.http.post('mybackend', entity).pipe(
    tap<EntityType>(resp => dispatch(new CreateSuccess(resp))),
    catchError(error => dispatch(new CreateFailed(error)))
  ); 

现在在我调用 create() 的组件中,我正在监听这两个动作。

this.actions$.pipe(
  ofActionSuccessful(CreateSuccess, UpdateSuccess),
  takeUntil(componentDestroyed(this)) // <--
).subscribe(action => doStuff());

这一切都完美无缺,唯一困扰我的是每次我使用它时,我都必须添加 takeUntil() 部分,以便在组件被销毁时取消订阅。

我知道这对每个人来说可能不是一个真正的问题,但我想知道是否有更清洁的方法来做到这一点。

我考虑过一个可以处理这个问题的自定义 RxJS 运算符,但也许还有其他选项,或者(我还没有找到任何东西),NGXS 有没有办法自己取消订阅?

【问题讨论】:

您有什么理由直接订阅这些操作?通常,您应该能够只订阅状态,然后在模板中使用异步管道来完成状态的所有呈现。异步管道将处理所有退订。 @lupus137 在这个具体的例子中,我正在使用一个对话框,我想在操作成功后关闭对话框,所以很遗憾无法使用它。 我通常做的是在状态上保留一个变量,指示对话框是否需要打开(例如:isDialogOpen)。然后,您可以将模式/对话框的打开/关闭绑定到该变量。这样,在操作成功后将变量设置为 false 应该关闭模态! 【参考方案1】:

在 NGXS 中,dispatch 方法返回一个 observable,一旦操作处理完成(无需取消订阅),该 observable 就会完成。因此,在您的示例中,您的 Create 操作将在操作的处理程序完成时完成。如果处理程序返回一个可观察对象(就像您所做的那样),那么完成将链接到该可观察对象的完成。如果您使用map 而不是tap 来调度CreateSuccess 操作,那么原始的observable 将等待那个'child' observable 首先完成。 我会像这样构造处理程序,以使 Create 操作仅在 CreateSuccess 完成后完成:

@Action(Create)
create( dispatch : StateContext<StateInterface>,  entity: Create) 
  return this.http.post('mybackend', entity).pipe(
    map<EntityType>(resp => dispatch(new CreateSuccess(resp))),
    catchError(error => dispatch(new CreateFailed(error)))
  ); 

然后在你的组件中你可以这样做:

create() 
  this.store.dispatch(new Create(this.form.value))
    .subscribe(action => doStuff()); 

当分派动作的处理(和“子”动作处理)完成时,observable 将完成。无需退订。

【讨论】:

谢谢!这听起来像是一个可能的变体,但有什么方法可以知道请求是成功还是失败?并获得动作的返回值?我认为有一个限制,无法确定返回值,对吧? subscribe 方法确实允许您为 next、error 和 completed 提供回调。不幸的是,动作响应的值不可用,因为它是多播调度。我假设该值会在您所在的州出现,因此您可以使用store.selectSnapshot 来获取它【参考方案2】:

NGXS 不提供任何基于 Angular 组件生命周期退订的特殊功能。

通常,在组件被销毁时取消订阅是有意义的。但是,在某些情况下,您需要更具体地控制何时订阅/取消订阅。

因此,您必须在每个 Angular 组件的相应生命周期函数中对其进行管理。

【讨论】:

以上是关于使用 NGXS 订阅操作流的更简洁方式的主要内容,如果未能解决你的问题,请参考以下文章

使用 http 服务从操作 (NGXS) 中返回一个值

Pipe and Tap VS 使用 ngxs 订阅

我们应该取消订阅 ngxs Selector 吗?

@ngxs/form-plugin:处理单个字段更改

try with resources简洁的异常捕获机制

在 NGXS 操作中调用后尝试关闭材料小吃吧不起作用