Redux-observable 高级概念及实践

阅读时长 10 分钟读完

在 React 应用中,Redux 已经成为了状态管理的首选解决方案之一。如果你已经熟悉了 Redux 的基本使用方法,那么你可能会发现,在一些复杂的应用场景中,Redux 中的 Action 和 Reducer 已经难以满足你的需求。在这种情况下,Redux-observable 可以成为一个非常好的工具来帮助你更加灵活地管理应用状态。

Redux-observable 是一个基于 RxJS 的 Redux 中间件,它允许你使用 RxJS 的 Observable 来处理异步操作和副作用。本文将深入介绍 Redux-observable 的高级概念及实践,包括以下内容:

  • Epic 的概念与实现
  • 在 Epic 中使用通用副作用库
  • 使用 Redux-observable 处理流程输入与输出

Epic 的概念与实现

在 Redux-observable 中,Epic 可以被认为是一种特殊的 Redux 中间件,它会接收到所有的 Redux Action,并返回一个新的 Action 流,这个新的流可能包含多个 Action 或者根本不包含任何 Action。在处理这个 Action 流的过程中,Epic 可以使用 RxJS 中的各种操作符和 Observables 对这个流进行操作。

下面是一个基本的 Epic 的实现:

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

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

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

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

在这个 Epic 中,我们监听了 FETCH_USER Action,并使用 rxjs/ajax 去请求用户数据。如果请求成功,我们就 dispatch 了一个新的 Action,包含用户数据,如果请求失败,我们同时 dispatch 了一个错误 Action。

在实际的应用中,Epic 经常会使用工具库去处理 Async Action,例如 Redux Promise、Redux Saga 等等。但是,值得注意的是,Redux-observable 是唯一一种允许你使用 RxJS 操作符和 Observables 来处理 Action 流的 Redux 中间件。

在 Epic 中使用通用副作用库

在 Epic 的开发过程中,经常会遇到需要使用各种异步操作的情况。一些常见的操作包括:

  • 测试输入数据的有效性
  • 与服务器交互
  • 访问浏览器的 Local Storage

虽然 RxJS 已经提供了很多操作符和 Observables 来完成这些操作,但是使用期间仍然需要大量的手动操作,这很容易带来一些烦恼。在这种情况下,副作用库可以成为一个非常好的解决方案。

和 React 的生命周期钩子函数类似,副作用库提供了一些回调函数,这些函数会在 Redux 中间件被调用的过程中自动触发。通过在这些回调函数中执行异步操作,我们可以非常简单地处理各种副作用,而不需要手动操作 RxJS。

下面是一个使用 universal-cookie 库来处理 Cookie 副作用的例子:

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

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

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

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

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

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

在这个 middleware 中,我们创建了一个名叫 cookieJar 的 cookie 实例,并注册了一个 Redux 中间件。当这个 middleware 被执行时,它会检查是否存在需要设置或删除 Cookie 的 Action,并执行相应操作。

这是一个非常简单的例子,然而通用副作用库真正的价值在于可以简化 Redux-observable 中处理副作用的代码量,同时还可以防止因为手动操作 RxJS 而带来的错误。在实际的项目中,你可以使用很多不同的库来简化中间件的开发,例如 Redux Offline、Redux Thunk 等。

使用 Redux-observable 处理流程输入与输出

我们已经在前面的部分介绍了如何使用 Redux-observable 来协调输入流,但是其实 Redux-observable 本身还提供了很多不同的工具,可以帮助你更好地管理 Action 流。下面我们将介绍一些这些工具以及使用方式。

combineEpics

combineEpics 工具可以将多个 Epic 组合在一起,并合并它们的输出流。它和 Redux 中的 combineReducers 工具非常类似,在一个简单的 Redux-observable 应用中,你可以使用这个工具将所有的 Epic 组合在一起。

下面是一个使用 combineEpics 的例子:

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

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

在这个示例中,我们将三个不同的 Epic 组合在一起,并导出一个最终的 Epic,这个 Epic 可以直接被传递给 Redux middleware。

catchError

catchError 操作符可以用来处理 Epic 中发生的错误。它可以捕获错误并派发一个新的 Action,然后继续处理后面的流程。在使用 Redux-observable 开发应用时,这个操作符可以非常方便地捕获和处理一些异常情况,并且避免因为异常而导致的应用崩溃。

下面是一个使用 catchError 的例子:

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

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

在这个例子中,我们使用 catchError 安全地处理 ajax.getJSON() 中可能会抛出的错误,并派发了一个错误 Action。

exhaustMap & mergeMap

在使用 Redux-observable 的时候,我们需要在不同的 Observable 之间切换。这个时候,exhaustMap 和 mergeMap 就可以帮助我们轻松地管理这些操作。

  • exhaustMap:如果有多个 Observable 在运行,它会忽略所有新的 Observable,直到当前 Observable 完成之后再继续执行下一个 Observable。即使在这过程中有新的 Observable 被添加到队列中,它也会被忽略。

下面是一个使用 exhaustMap 的例子:

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

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

在这个例子中,我们使用 exhaustMap 来忽略中间的 Action,只保留最后一个 Action,这可以帮助我们避免并行发起多个 API 请求。

  • mergeMap:如果有多个 Observable 在运行,它会同时发起所有新的 Observable 并等待所有 Observable 都完成之后继续执行下一个 Observable。

下面是一个使用 mergeMap 的例子:

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

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

在这个例子中,我们使用 mergeMap 同时发起了多个 API 请求,并等待所有 Observable 完成之后再继续执行下一个 Observable。

结论

通过本文,你已经了解了如何使用 Redux-observable 来更好地管理应用的状态,并掌握了一些关键的工具和技术。虽然 Redux-observable 的学习曲线比较陡峭,但是在一些复杂的应用场景中,它可以帮助你更加灵活地管理状态,同时也可以避免因为手动处理 RxJS 导致的错误。在实际的项目中,你可以将 Redux-observable 和其他工具库结合起来使用,去创造出更好的应用。

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

纠错
反馈