【问题标题】:takeEvery and takeLatest. Why? When to use? Use simultaneously?takeEvery 和 takeLatest。为什么?什么时候使用?同时使用?
【发布时间】:2020-05-24 09:57:45
【问题描述】:

我不清楚何时使用 takeEvery 以及何时使用 takeLatest ?在 redux-saga 中。

通过阅读官方文档,我得到了一个基本的区别。但是在 takeEvery 中创建并发操作有什么用(例如,用户快速连续两次单击 Load User 按钮,第二次单击将在 fetchUser 触发时调度 USER_REQUESTED第一个尚未终止)

import { takeEvery } from `redux-saga/effects`

function* fetchUser(action) {
  ...
}

function* watchFetchUser() {
  yield takeEvery('USER_REQUESTED', fetchUser)
}

谁能解释一下。因为我对 redux-saga 完全陌生。

提前致谢。

【问题讨论】:

    标签: reactjs redux redux-saga


    【解决方案1】:

    虽然@Martin Kadlec 的可靠答案涵盖了这个问题,但我想详细说明 takeEverytakeLatest 的细节和差异以及何时可以使用它们您可以推导出它们的可能用例。

    TLDR:

    当需要所有先前任务的返回时,您可以使用 takeEvery。例如,从气象站获取一段时间内的温度和湿度数据,将其存储在数据库中并显示为图表 - 在这种情况下,所有以前的 saga 及其返回值都是相互交叉的,不仅仅是最新的强>。

    如果 i.E. 你可以使用 takeLatest内部/外部实例或界面的用户可能会触发多个连续动作,并且只有最后一个值的结论是可取的。一个很好的例子是快速调用经纪人 API 以获取股票价值的实时报价,其中只有最新/最近的价值是感兴趣的

    详细:

    takeEverytakeLatest 视为 redux-saga 底层 API 之上的辅助函数,它们封装了内部操作,例如在调度特定操作时生成任务到商店。调用它们会在调度到与模式匹配的 Store 的每个操作上产生一个 saga。

    takeEvery:

    最常见的 takeEvery 函数在其行为和方法上与 redux-thunk 非常相似。它基本上是模式或通道的yield takeyield fork 的包装器。

    关于 takeEvery 的线索是它允许同时/同时启动已定义操作/任务的多个实例(例如下面示例中的 fetchSomeThing)。

    takeLatest 不同,您可以在 fetchSomeThing 的一个或多个先前实例尚未完成/终止时开始新的 fetchSomeThing 任务,因此仍处于挂起状态。请记住,不能保证任务将以与启动相同的顺序终止/完成。要处理乱序响应,您可以使用 takeLatest

    来自官方docs

    takeEvery(pattern, saga, ...args)

    在发送到 Store 且匹配模式的每个操作上生成一个 saga。

    • pattern: 字符串 |数组 |功能
    • saga:函数 - 生成器函数
    • args: 数组 - 要传递给已启动任务的参数。 takeEvery 会将传入的动作添加到参数列表中(即动作将是提供给 saga 的最后一个参数)

    您还可以将通道作为参数而不是模式传递,从而产生与 takeEvery(pattern, saga, ...args) 相同的行为。

    takeLatest:

    相比之下,takeLatest 辅助函数只获取被触发的 latest 请求 的响应,并且可以看作是 yield take 的包装器模式或通道 和一个额外的 if 语句检查是否存在 lastTask(之前的任务仍处于挂起状态),然后将通过 yield cancel 和后续的 @ 终止987654334@ 将产生当前任务/动作。

    来自官方docs

    takeLatest(pattern, saga, ...args)

    只会得到最近触发的请求的响应。

    • pattern: 字符串 |数组 |功能
    • saga:函数 - 生成器函数
    • args: 数组 - 要传递给已启动任务的参数。 takeLatest 会将传入的动作添加到参数列表中(即动作将是提供给 saga 的最后一个参数)

    takeEvery 类似,您也可以将通道作为参数而不是模式传递。

    【讨论】:

      【解决方案2】:

      这是您真正需要考虑每个用例的事情。

      这些是您可以使用takeEvery 的一些情况。

      1. 对于非异步的 sagas,因此没有理由 取消它们。 takeLatest 也可以在这里工作,但它可能会给 读取代码时出现错误提示 取消。

      2. 有时,每次操作都以某种方式不同。例如。 假设您有一部电影,并且您正在添加带有流派的标签 电影。每次触发动作时,您都会获得不同的流派, 即使它是相同的动作类型。用户可以添加流派 比您从服务器获得响应快。但只是因为你 快速添加多种类型并不意味着您要停止传奇 添加上一个。

      3. 当你有相同的加载动作时的廉价实现 多个不同的项目。例如。你有电影列表,每个都有 “加载详细信息”按钮。 (让我们忽略一个事实,你应该 加载开始后可能会隐藏或禁用按钮)。这 一部电影的数据总是相同的,但它们之间的数据不同。 当您单击电影 1 的加载详细信息时,您不想取消 为电影加载数据 2. 因为它是电影的动态列表 动作类型每次都一样,区别是 可能类似于动作电影的id

        在理想的实现中,您可能应该取消之前的加载传奇 相同的电影/ID,但这需要更复杂的代码和 所以如果你只做一些简单的应用程序,你可能会决定忽略 那并且只允许多次运行同一部电影的传奇。 这就是我称之为“廉价实现”的原因。

      【讨论】:

      • 可靠的答案 - 我希望你不介意我在下面的答案中也详细说明一下细节;)
      【解决方案3】:

      一句话总结,

      • takeEvery 允许处理并发操作。例如,用户快速连续两次单击加载用户按钮,第二次单击将调度 USER_REQUESTED 操作,而第一次触发的 fetchUser 尚未终止。
        takeEvery 不处理来自任务的乱序响应。不能保证任务会按照它们开始的顺序终止。要处理乱序响应,您可以考虑 takeLatest。
      • takeLatest 改为在每个分派的 USER_REQUESTED 操作上启动一个新的 fetchUser 任务。由于 takeLatest 取消之前启动的任何待处理任务,我们确保如果用户快速触发多个连续的 USER_REQUESTED 操作,我们将仅以最新操作结束

      文档:https://redux-saga.js.org/docs/api/

      【讨论】:

        【解决方案4】:
        • takeEvery - 允许同时使用多个 fetchData 对象。 在给定的时刻,我们可以在那里启动一个新的 fetchData 任务 仍然是一个或多个之前没有的 fetchData 任务 尚未终止。

        • takeLatest - 在任何给定时刻只能激活一个 fetchData 任务。它 也将是最近开始的工作。如果一个新的 fetchData 作业在前一个任务仍在运行时启动, 之前的工作将立即终止。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-06-04
          • 2017-09-13
          • 1970-01-01
          • 1970-01-01
          • 2013-06-11
          • 2022-11-10
          相关资源
          最近更新 更多