【问题标题】:How to divide the logic between Redux reducers and action creators?Redux reducer 和 action creators 之间的逻辑如何划分?
【发布时间】:2016-03-09 23:07:25
【问题描述】:

我已经将一些逻辑放入减速器中,我认为应该将其放入 Action 并传递下去?

将这类东西放在 action 或 reducer 中是最佳做法吗?

工作示例here

减速机代码:

function Card() {
  this.card = (Math.random()*4).toFixed(0);
}

Card.prototype = {
  getRandom: function(){
    var card;
    //console.log(this.card)
    switch (this.card) {
      case '1':
      card = 'heart';
      break;
      case '2':
      //card = 'diamonds';
      card = 'heart'; // weight the odds abit
      break;
      case '3':
      card = 'club';
      break;
      case '4':
      card = 'spade';
      break;
      default:
      card = 'heart';
      break;
    }
    return card;
  }
}

var dealer = {
  deal: function(){
    var results = [];
    for(var i = 0; i <4; i++){
      var card = new Card();
      results.push(card.getRandom());
    }
    console.log(results);
    return results;
  }
}


const initialState = {
  count: 0,
  data: []
}

function counter (state = initialState, action) {
  let count = state.count
  switch (action.type) {
    case 'increase':
      return Object.assign({}, state, {
        data: dealer.deal(),
        count: state.count+1
      })
    default:
      return state
  }
}

【问题讨论】:

  • Reducer 应该包含改变状态的逻辑,但最好不要将其写在 switch 语句中,而是将逻辑提取到一个单独的函数中,传递当前状态并返回新状态。一个很棒的教程:teropa.info/blog/2015/09/10/…
  • "Reducer 应该包含改变状态的逻辑" ?
  • reducer 应该包含所有改变给定状态的逻辑。但最好的做法是提取此逻辑以分隔函数,而不是在 case 语句之间内联编写它,例如:return addUsers(currentState, action) -&gt; newState

标签: javascript reactjs redux


【解决方案1】:

看起来最好有一个静态类来处理在 redux 之外实例化 redux 操作的第一级入口点。

我认为保持 store 和 action 链的纯净是有意义的。

一开始这可能看起来像很多重复的代码,但是当您开始根据条件进行调度或需要从多个地方进行调度时,它开始打开并变得有意义。

【讨论】:

    【解决方案2】:

    你的 reducer 必须是纯的。目前它并不纯净。它调用deal(),后者调用getRandom(),后者依赖于Math.random(),因此不纯。

    这种逻辑(“生成数据”,无论是随机的还是来自用户输入的)都应该在动作创建器中。动作创建者不需要是纯粹的,并且可以安全地使用Math.random()。这个动作创建者会返回一个动作,一个描述变化的对象

    {
      type: 'DEAL_CARDS',
      cards: ['heart', 'club', 'heart', 'heart']
    }
    

    reducer 只会在状态中添加(或替换?)这些数据。

    一般来说,从一个动作对象开始。它应该以这样一种方式描述变化,即使用相同的动作对象和相同的先前状态运行reducer应该返回相同的下一个状态。这就是为什么 reducer 不能包含 Math.random() 调用的原因——它们会打破这个条件,因为它们每次都是随机的。你将无法测试你的减速器。

    在你弄清楚动作对象的外观之后(例如像上面那样),你可以编写动作创建器来生成它,并编写一个减速器来将状态和动作转换到下一个状态。 生成动作的逻辑存在于动作创建者中,对其作出反应的逻辑存在于reducer中,reducer必须是纯的。

    最后,不要在状态内使用类。它们不能按原样序列化。你不需要 Card 类。只需使用普通对象和数组即可。

    【讨论】:

    • 在动作创建器中生成动作背后的逻辑是什么?如果该逻辑存储在减速器中怎么办? (我假设逻辑是纯粹的)那有什么问题?我查看了 redux + elm 文档,但找不到任何参考。您介意详细说明/将我指向正确的文档吗?
    • @danielepolencic 恐怕这是一个模糊的问题。如果你提供一个具体的例子,我很乐意讨论。
    • @danielepolencic 如果逻辑在动作创建者中,那么重放创建的动作将始终产生相同的状态。如果逻辑在 reducer 中,则不能保证重放操作的结果是相同的。在某些情况下这可能无关紧要,但如果您希望 redux 开发工具正常工作,这是必需的。
    【解决方案3】:

    我的理解是,动作应该是包含两件事的简单对象:(i) 动作类型和 (ii) 发生了什么变化(即新数据)。

    另一方面,Reducer 是纯函数,它们将操作和之前的应用程序状态作为输入并返回新的应用程序状态。他们如何做到这一点取决于你。您可以添加任何必要的逻辑来组合先前的状态 + 操作并返回新状态只要您不在 reducer 函数之外改变数据。

    至于您的代码,我不确定deal() 函数属于动作还是减速器。我认为更好的地方可能是某种事件处理程序(例如onClick)。然后,您可以将交易调用的 results 作为操作传递给 reducer。

    【讨论】:

    • 抱歉详细说明:我的意思不是在动作内部,我是指动作代码(在模块中)。我开始认为在某种 utils 模块中可能?
    • 是的,我喜欢让我的动作模块非常简单。基本上只是一堆返回类型和新数据的函数。新数据是如何从其他地方获得的。
    猜你喜欢
    • 2016-12-04
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多