Redux reducers 和 action creators 之间的逻辑如何划分?

IT技术 javascript reactjs redux
2021-04-01 12:15:20

我有一些我已经放入减速器的逻辑,我认为应该可能放入 Action 并传递下去?

将这种东西放在动作或减速器中是最佳实践吗?

工作示例在这里

减速机代码:

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
  }
}
3个回答

你的减速机必须是纯的。目前它不纯。它调用deal()which 调用getRandom()which 依赖Math.random(),因此不是纯的。

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

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

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

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

在弄清楚 action 对象的外观后(例如像上面那样),您可以编写 action creator 来生成它,并编写一个 reducer 来将 state 和 action 转换为下一个状态。生成动作的逻辑驻留在动作创建者中,对其作出react的逻辑驻留在reducer中,reducer必须是纯的。

最后,不要在 state 内部使用类它们不能按原样序列化。你不需要Card上课。只需使用普通对象和数组。

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

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

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

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

是的,我喜欢让我的动作module非常简单。基本上只是一堆返回类型和新数据的函数。新数据是如何从其他地方获得的。
2021-05-29 12:15:20
抱歉只是要详细说明:我不是指在动作内部,而是指动作代码(在module中)。我开始认为在某种 utils module中是可能的?
2021-06-11 12:15:20

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

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

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