在 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