如何编写第一个 ngrx Effect 类

举报
汪子熙 发表于 2022/08/28 10:00:45 2022/08/28
【摘要】 官网要将副作用与您的组件隔离,您必须创建一个 Effects 类来侦听事件并执行任务。Effect 是具有不同部分的可注入服务类:一个可注入的 Actions 服务,它提供了在 reduce 最新状态后调度的所有操作的可观察流。如下图所示:使用 createEffect 函数将元数据附加到可观察流。 元数据用于注册订阅存储的流。从 effect 流返回的任何操作都会被分派回 Store。使用...

官网

要将副作用与您的组件隔离,您必须创建一个 Effects 类来侦听事件并执行任务。

Effect 是具有不同部分的可注入服务类:

  • 一个可注入的 Actions 服务,它提供了在 reduce 最新状态后调度的所有操作的可观察流。

如下图所示:

  • 使用 createEffect 函数将元数据附加到可观察流。 元数据用于注册订阅存储的流。从 effect 流返回的任何操作都会被分派回 Store。

  • 使用可管道化的 ofType 运算符过滤操作。 ofType 运算符将一种或多种操作类型作为参数来过滤要执行的操作。

如下图所示:

  • effects 订阅了 Store observable.

  • 服务被注入到效果中以与外部 API 交互并处理流。

看一个实际的 effects 实现例子:

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { EMPTY } from 'rxjs';
import { map, mergeMap, catchError } from 'rxjs/operators';
import { MoviesService } from './movies.service';

@Injectable()
export class MovieEffects {

  loadMovies$ = createEffect(() => this.actions$.pipe(
    ofType('[Movies Page] Load Movies'),
    mergeMap(() => this.moviesService.getAll()
      .pipe(
        map(movies => ({ type: '[Movies API] Movies Loaded Success', payload: movies })),
        catchError(() => EMPTY)
      ))
    )
  );

  constructor(
    private actions$: Actions,
    private moviesService: MoviesService
  ) {}
}

loadMovies$ 效果通过 Actions 流监听所有 dispatch 的 action,但只对使用 ofType 操作符的 [Movies Page] Load Movies 事件感兴趣。

我们必须使用 ofType 来过滤事件,应该通过构造函数依赖注入得到的 action 实例是一个单例,默认会捕捉到系统所有 dispatch 的事件。

然后使用 mergeMap 运算符将 action 流展平,并映射到新的可观察对象中。 MoviesService#getAll() 方法返回一个 observable,该 observable 将电影映射到成功的新 action,如果发生错误,当前返回一个空的 observable。

当需要更改状态时,action 被分派到 Store,在那里它可以由 reducer 处理。 在处理可观察流时处理错误也很重要,这样 effect 才能继续运行。

Registering root effects

编写 Effects 类后,必须注册它,以便效果开始运行。 要注册根级 effects,请将 EffectsModule.forRoot() 方法与您的 effect 数组添加到您的 AppModule。

下面是 app.module.ts 的例子:

import { EffectsModule } from '@ngrx/effects';
import { MovieEffects } from './effects/movie.effects';

@NgModule({
  imports: [
    EffectsModule.forRoot([MovieEffects])
  ],
})
export class AppModule {}

即使您没有注册任何根级效果,也必须将 EffectsModule.forRoot() 方法添加到您的 AppModule 导入中。

下面的代码来自 Spartacus 的 app.module.ts:

效果在 AppModule 加载后立即开始运行,以确保它们尽快侦听所有相关操作。

Registering feature effects

对于功能模块,通过在 NgModule 的导入数组中添加 EffectsModule.forFeature() 方法来注册你的 effect。

例子:

import { EffectsModule } from '@ngrx/effects';
import { MovieEffects } from './effects/movie.effects';

@NgModule({
  imports: [
    EffectsModule.forFeature([MovieEffects])
  ],
})
export class MovieModule {}

通过 forRoot() 或 forFeature() 多次运行效果类(例如通过不同的延迟加载模块)不会导致效果多次运行。 forRoot() 和 forFeature() 加载的效果之间没有功能差异; 函数之间的重要区别在于 forRoot() 设置 Effects 所需的 providers 程序。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。