NgRx 与 RxJS: 一个应用实战

阅读时长 13 分钟读完

前言

在前端开发中,状态管理是非常重要的一部分。而随着现代化 Web 应用逐渐兴起,单向数据流架构也成为越来越多开发者的选择。NgRx 就是 Angular 中的一种实现单向数据流的解决方案,它的核心依赖——RxJS 也是前端开发者必须掌握的一项技能。

本文将会介绍如何在 Angular 应用中使用 NgRx/RxJS 进行状态管理。为了让读者有一个更加直观的理解,我们将通过一个简单的 TodoList 应用来进行演示。我们将探讨以下主题:

  1. 如何使用 NgRx Store 来管理状态
  2. 如何使用 NgRx Effect 来处理异步请求
  3. 如何使用 RxJS 来过滤和转换数据

安装依赖

在开始之前,请先确保已经安装了 Angular CLI,并创建了一个空的 Angular 项目。我们需要安装一些 NgRx 相关的依赖:

然后,我们需要引入 RxJS。RxJS 也是一个非常强大的库,它提供了一系列的操作符和 Observable,可以方便地进行各种数据流的处理。我们可以这样安装:

当然,为了实现 TodoList 应用的界面,我们还需要 angular-material 和 flex-layout。这里不再多赘述,请读者自行安装。

创建 Store 和 Actions

我们需要先思考一下 TodoList 应用中都有哪些状态需要管理。这里我们只考虑最简单的 TodoList,所以只需要考虑以下两个状态:

  1. TodoList 中所有的任务列表
  2. 当前被选中的任务

我们在应用的根目录中新建一个叫做 store 的文件夹,然后在该文件夹中创建一个 actions.ts 文件:

-- -------------------- ---- -------
------ - ------------- ----- - ---- --------------

------ ----- ------- - -------------
  ----------- --- ------
  ------- ----- ------ ----
--

------ ----- ---------- - -------------
  ----------- ------ ------
  ------- --- ------ - ---- ----
--

------ ----- ---------- - -------------
  ----------- ------ ------
  ------- --- ------ ----
--

------ ----- ---------- - -------------
  ----------- ------ ------
  ------- --- ------ ----
--

actions.ts 文件中,我们定义了 4 个 Action:addTask、selectTask、deleteTask 和 toggleTask,分别对应添加任务、选择任务、删除任务和完成任务等操作。其中,每一个 Action 都有一个对应的字符串类型('[TodoList] Add Task'),它们是用来区分这个 Action 的,也就是用来告诉 Store 要对这个 Action 做出什么样的改变。

注意:这里的 '[TodoList]' 前缀是可以自己定义的。本文中,为了方便区分不同的 Action,我们把它们都放在了 [TodoList] 的命名空间下。

接着,我们继续在 store 文件夹下创建一个 reducers.ts 文件:

-- -------------------- ---- -------
------ - -------------- -- - ---- --------------
------ - -------- ----------- ----------- ---------- - ---- ------------

------ --------- ---- -
  --- -------
  ----- -------
  ---------- --------
-

------ --------- ----- -
  ------ -------
  ----------- ------ - -----
-

------ ----- ------------- ----- - -
  ------ ---
  ----------- ----
--

------ ----- ----------- - --------------
  -------------
  ----------- ------- - ---- -- -- --
    ---------
    ------ -
      ---------------
      - --- ---------------------------------------- ----- ---------- ----- -
    -
  ----
  -------------- ------- - -- -- -- --
    ---------
    ----------- --
  ----
  -------------- ------- - -- -- -- --
    ---------
    ------ ----------------------- -- ------- --- ---
  ----
  -------------- ------- - -- -- -- --
    ---------
    ------ -------------------- --
      ------- --- -- - - -------- ---------- --------------- - - ----
    -
  ---
--

在这里,我们定义了一个叫做 todoReducer 的 Reducer。它包含两个状态:todosselectedId。在 initialState 中,我们初始化了这两个状态的默认值。然后我们使用 createReducer 方法来创建这个 Reducer,它将接收多个类似于 on(addTask, reducerFunction) 的对象作为参数。在这其中,每一个对象将会对应一个 Action,并且它会接收一个 Reducer 函数作为第二个参数。这个 Reducer 函数将会在 Action 被触发的时候被执行。

在本例中,我们将 Reducer 函数命名为 todoReducer,然后它接收四个 Action,并且执行相应的操作,以改变 Store 中的状态值。具体地讲,我们在 addTask 中添加了一个新的任务,在 selectTask 中选择了当前的任务,在 deleteTask 中删除了指定的任务,而在 toggleTask 中切换了任务的完成状态。

创建 Effects

接着,我们需要处理一下异步操作。对于 TodoList 应用来说,最常见的异步操作可能就是从服务器端加载数据了。我们可以在 store 文件夹下再新建一个 effects.ts 文件:

-- -------------------- ---- -------
------ - ---------- - ---- ----------------
------ - -------- ------------- ------ - ---- ----------------
------ - -- - ---- -------
------ - ---------- ----------- --- - ---- -----------------
------ - ----------- - ---- ------------------
------ - ------- - ---- ------------

-------------
------ ----- ----------- -
  --------- - --------------- --
    -------------------
      ------------------ ---- -------
      ------------ --
        ------------------------------------
          --------- -- --------- ----- ----- ----
          ------------- -- ---- ----- ----------- ---- ---- -------- ---
        -
      -
    -
  --

  ------------------- --------- -------- ------- ------------ ------------ --
-

首先,我们要注入一个 TodoService,用来从服务器端加载数据。然后,我们定义了一个叫做 loadTodo$ 的 Effect,在这个 Effect 中,我们使用 switchMap 操作符将 getTodoList() 的结果映射为 addTask 关联的任务对象。如果操作成功,它将返回一个 addTask Action,并且任务将被添加到 TodoList 中。如果操作失败,我们将返回一个 Load Todo Failure 的 Action。

effects.ts 文件中,我们还需要定义一个 EffectsModule 来将 TodoEffects 注册到我们的应用程序中。我们可以在 AppModule 中这样写:

-- -------------------- ---- -------
------ - -------- - ---- ----------------
------ - ------------- - ---- ----------------------------
------ - ---------------- - ---- -----------------------
------ - ------------ - ---- ------------------
------ - ----------------------- - ---- ---------------------------------------
------ - ---------------- - ---- -----------------------
------ - ----------- - ---- --------------
------ - ------------- - ---- ----------------
------ - ------- - ---- -------------------
------ - ----------- - ---- ------------------

-----------
  ------------- ---------------
  -------- -
    --------------
    -----------------
    ------------------------
    -----------------
    --------------------- ---------- ------- ---
    ------------------------------------
  --
  ---------- ---
  ---------- --------------
--
------ ----- --------- --

注意:在这里,我们使用了 forRoot 方法来注册 Reducer 和 Effects。如果你的应用程序是一个子模块,你应该使用 forFeature 方法来注册它们。

结合 RxJS 处理数据

现在,我们已经完成了 Store 和 Effects 的创建。但是,我们还需要通过 RxJS 来处理数据,才能使我们的 TodoList 更加有效和可读。我们可以在 todo-list.component.ts 文件中这样写:

-- -------------------- ---- -------
------ - ---------- ------ - ---- ----------------
------ - ----- - ---- --------------
------ - ---------- - ---- -------
------ - ------ - ---- -----------------
------ - -------- ----------- ----------- ---------- - ---- -------------------
------ - ------ ---- - ---- --------------------

------------
  --------- ----------------
  ------------ -----------------------------
  ---------- ------------------------------
--
------ ----- ----------------- ---------- ------ -
  ------- ------------------ - --- ---------------------
  ------------ ----------------- - ----- - --- ----------------- - --------
  ----- ------ - ---

  ------------------- ------ ------- ---------- ----- --- --

  ---------- -
    ----------- - ----------------------- -- -----------------------
    ---------------- - ----------------------- -- ----------------------------
  -

  -------------- ----- -
    -------------------------------- --- ------- ----
  -

  ------------ ------- -
    -------------------------------- -- ----
  -

  ------------ ------- -
    -------------------------------- -- ----
  -

  ---------- -
    -- ----------------- --- --- -
      -------
    -
    ----------------------------- ----- --------- ----
    --------- - ---
  -

  --- ---------------- ---------------- -
    ------ -----------------
      ------------ -- ---------
      ------------ -- --------------------
      ------------ -- ----------------- -- ------- --- -------------------
      --------- -- --------------- -- ------- --- ------------------
    --
  -
-

在上面的代码中,我们让应用程序能够选择任务(onSelect)、删除任务(onDelete)和完成任务(onToggle)。同时,我们也允许用户添加新的任务。这些方法都包含在这个组件中,但是我们需要将它们和 Store 中的状态值联系起来。

首先,我们需要订阅 selectedId$todos$ 这两个 Observable。然后,我们可以定义一个 selectedTask$ 的 Observable,它将只会发射被选中的任务。我们可以通过使用 filtermap 操作符来实现这一点。我们还可以通过 pipesubscribe 来创建其他的 Observable,以便我们可以更好地控制数据的流动。

结论

至此,我们已经完成了使用 NgRx 和 RxJS 来构建一个 TodoList 的应用的全部内容。NgRx Store 负责管理我们的应用程序状态,NgRx Effect 允许我们通过异步的方式来调用服务器端的 API,而 RxJS 则将作为数据处理的主要工具,方便我们对数据做各种转换和处理。

本文介绍了在 Angular 应用中如何使用 NgRx 和 RxJS 这两个库来构建 TodoList 应用。我们从定义 Reducer 开始,然后介绍了如何处理异步操作,并通过 RxJS 的操作符和 Observable 配合起来进行数据转换和处理。本文的示例代码可从 Github仓库 下载,供读者参考学习。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/671c34d49babaf620faf9a75

纠错
反馈