React Redux 中的异步操作与副作用

在 React 应用中,数据流管理是一个核心问题,特别是在大型复杂应用中。Redux 是一个流行的状态管理库,它为我们提供了单一的数据源。但是,如果我们需要在 Redux 中进行异步操作,如何实现呢?本文将介绍 Redux-Thunk 和 Redux-Saga 这两个常用库来实现异步操作和副作用的处理。

异步操作

在实际开发中,我们可能需要在 Redux 中进行异步操作,如请求服务器获取数据、动态更新 UI 等操作。但是,Redux 本身只支持同步操作,因此我们需要使用一些库实现异步操作。

Redux-Thunk

Redux-Thunk 是一个流行的 Redux 异步操作中间件,它允许我们在 Redux 的 action 中执行异步操作并返回一个函数。这个函数接收 dispatch() 方法作为参数,使我们可以异步地调用 action 方法。

下面是一个简单的 Redux-Thunk 示例:

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

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

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

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

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

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

在这里,我们定义了一个 loadData() 函数,它返回一个函数。这个函数接收 dispatch() 方法作为参数,并在异步请求数据后发送 LOAD_DATA_SUCCESS 或 LOAD_DATA_FAILURE action。在组件中使用 connect() 方法将 loadData() 方法注入到 props 中,并在组件挂载后调用。当数据加载时,Redux store 中的数据将更新并触发组件重新渲染。

Redux-Saga

与 Redux-Thunk 不同的是,Redux-Saga 通过使用 Generator 函数来实现异步操作。它使用了 ES6 的 Generator 函数和 yield 表达式,使我们能够以声明的方式编写异步代码。

下面是一个简单的 Redux-Saga 示例:

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

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

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

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

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

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

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

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

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

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

在这里,我们定义了一个 loadData() 方法,它触发 LOAD_DATA action。在 sagas.js 中,我们使用 takeEvery() 方法监听 LOAD_DATA action,并在获取数据时使用 call() 方法使 fetch() 函数变成异步的。在 fetchData() 中,我们使用 try/catch 语句来处理异步请求的结果,并使用 put() 发送 LOAD_DATA_SUCCESS 或 LOAD_DATA_FAILURE action。最后,我们在 rootSaga() 中使用 all() 方法来启动 watchFetchData() 任务。这个任务将 LISTEN_FOR_DATA action 与 fetchData() 方法相关联。

副作用

副作用是指 Redux store 中状态改变后除了更新数据状态外对其他系统组件和特定环境产生的变化,包括但不限于 API 请求、I/O 操作、路由跳转、定时器回调等等。Redux 的设计哲学在很大程度上是为了避免副作用。然而,有时候我们确实需要处理副作用的情况,这就需要使用副作用管理库来处理这些事情。

Redux-Saga

Redux-Saga 是一个流行的处理副作用的库,它以 Daemon 进程的形式运行,监听和处理事件,以响应和触发 Redux action。应用 Redux-Saga 可以使应用程序变得更加可预测,易于测试和维护。

下面是一个简单的 Redux-Saga 副作用管理示例:

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

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

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

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

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

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

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

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

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

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

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

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

在这里,我们定义了两个 action,一个是 loadData() 用于触发 LOAD_DATA action,另一个是 cancelLoadData() 用于触发 CANCEL_LOAD_DATA action。在 sagas.js 中,我们使用 takeLatest() 方法监听 LISTEN_FOR_DATA action,并在获取数据时使用 call() 方法使 fetch() 函数变成异步的。在 fetchData() 中,我们使用 try/catch 语句来处理异步请求的结果,并使用 put() 发送 LOAD_DATA_SUCCESS 或 LOAD_DATA_FAILURE action。同时,我们使用 cancelled() 方法来检测任务是否被取消。在 cancelFetchData() 中,我们取消未完成的 fetch 请求。在 rootSaga() 中使用 all() 方法来启动 watchFetchData() 任务和 takeLatest("*", cancelFetchData) 任务。最后,当组件卸载时,我们调用 cancelLoadData() 方法以取消当前的请求。

结论

在本文中,我们介绍了 Redux-Thunk 和 Redux-Saga 这两个常用库来实现异步操作和副作用的处理。Redux-Thunk 通过函数式编程的方式实现了异步处理,Redux-Saga 则通过 Generator 函数的方式,提供了一种易于测试和维护的异步解决方案。对于副作用的处理,Redux-Saga 提供了一种易于控制的方式。我们可以根据具体的业务需求选择不同的方案。这些库虽然有一些学习曲线,但是一旦掌握,它们将使我们更加容易地管理和处理复杂的前端应用程序。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/670b8d03d91dce0dc88b306a