React Redux 中的纯动作是什么?

What are pure actions in React Redux?

我正在学习redux saga但不明白作者在下面的意思:

Contrary to redux thunk, you don't end up in callback hell, you can test your asynchronous flows easily and your actions stay pure.

任何“回调地狱”和“纯操作”的例子都将不胜感激。

纯函数

纯函数是一种函数,当给定相同的参数时,总是产生相同的结果,并且不会修改任何超出其作用域的变量.例如,

function addTwoIntegers(a, b) {
    return a + b;
}

如果我们传递 a=2 和 b=3,那么结果将始终为 5。没有其他任何改变。这是一件好事,因为它使测试该功能变得更加容易 - 我们可以肯定地知道对于给定的输入对,它们将输出什么。

例如,将此与从 API 加载数据并将其分配给变量的函数进行对比:

let result;

function AddIntegerToNumberFromServer(a) {
    fetch('api/numberGenerator').then(function(res) {
       result = a + res.data.number;
    });
}

在这种情况下,我们可以使用相同的参数多次调用该函数,但不确定是否会得到相同的结果。这样做的结果是函数更难测试——我们可能必须创建一个 api 的模拟。我们还必须确定 result 的初始值是多少,以便知道我们的函数是否按计划工作。

回调地狱

您可能知道,回调是我们作为参数传递给另一个函数的函数,这样我们就可以推迟执行某些代码,直到第二个函数完成。当我们深入其中时,回调地狱就会发生——正如上面某人评论的那样 jQuery 似乎邀请了这种风格——例如:

$(function() {
    $('#element').click(function() {
        $(this).fadeOut(function() {
            $('#anotherElement').fadeIn();
        }
    }
}

这里的问题主要是人类对代码的理解和可读性。想象一下,如果这更深入(并不少见),那么要弄清楚发生了什么以及何时发生会有多困难。

Redux-thunk 在回调方面远非最糟糕的违规者,并且可以通过使用承诺而不是回调来减轻可读性因素。

... your actions stay pure ...

我最好的猜测是这是一个错误。在 the redux-thunk README 中没有不纯的动作创建者,更不用说不纯的动作对象了。也许 "impure actions" 指的是 "higher level" action-creatorsmakeSandwichesForEverybody 这样的模式包含多种副作用,因此很难测试。

... end up in callback hell ...

同样 makeSandwichesForEverybody 包含许多嵌套的承诺,随着异步工作流程变得更加复杂,这些承诺可能会变得更难理解。我还不能评论的是这将在 redux-saga 中实现多少简单/复杂。

function makeSandwichesForEverybody() {
  return function (dispatch, getState) {
    if (!getState().sandwiches.isShopOpen) {

      // You don’t have to return Promises, but it’s a handy convention
      // so the caller can always call .then() on async dispatch result.

      return Promise.resolve();
    }

    // We can dispatch both plain object actions and other thunks,
    // which lets us compose the asynchronous actions in a single flow.

    return dispatch(
      makeASandwichWithSecretSauce('My Grandma')
    ).then(() =>
      Promise.all([
        dispatch(makeASandwichWithSecretSauce('Me')),
        dispatch(makeASandwichWithSecretSauce('My wife'))
      ])
    ).then(() =>
      dispatch(makeASandwichWithSecretSauce('Our kids'))
    ).then(() =>
      dispatch(getState().myMoney > 42 ?
        withdrawMoney(42) :
        apologize('Me', 'The Sandwich Shop')
      )
    );
  };
}

顺便说一句,我使用了 "impure action creators", which I call dispatchers 作为动作创建者、调度器并具有副作用的函数形式。我发现这是管理异步工作的好模式。然而,它使同构应用程序更难/不可能实现并且不容易测试。