如何划分 Redux reducer 和 action creator 之间的逻辑?
How to divide the logic between Redux reducers and action creators?
我在 reducer 中放入了一些逻辑,我认为应该将其放入 Action 中并传递下去?
将这类东西放在动作或减速器中是最佳实践吗?
工作示例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
}
}
我的理解是动作应该是包含两件事的简单对象:(i) 动作类型和 (ii) 改变的内容(即新数据)。
另一方面,Reducers 是纯函数,它将操作和先前的应用程序状态作为输入,return 新的应用程序状态。他们如何实现这一点取决于您。您可以添加任何必要的逻辑来结合先前的状态 + 操作和 return 新状态 只要您不在 reducer 函数之外改变数据。
具体到您的代码,我不确定 deal()
函数属于动作还是减速器。我认为更好的地方可能是某种事件处理程序(例如 onClick
)。然后,您可以将交易调用的 results 作为一个操作传递给您的减速器。
你的reducer必须是纯的。目前还不纯。它调用 deal()
调用 getRandom()
依赖于 Math.random()
因此不是纯粹的。
这种逻辑(“生成数据”,无论是随机的还是来自用户输入)应该在动作创建者中。动作创作者无需纯粹,可以放心使用Math.random()
。此操作创建者将 return 一个操作,一个描述更改的对象:
{
type: 'DEAL_CARDS',
cards: ['heart', 'club', 'heart', 'heart']
}
reducer 只会在状态中添加(或替换?)该数据。
一般来说,从一个action对象开始。它应该描述变化的方式是运行具有相同action对象和相同previous的reducer state 应该 return 相同的下一个状态。这就是为什么 reducer 不能包含 Math.random()
调用——它们会打破这个条件,因为它们每次都是随机的。您将无法测试您的减速器。
在弄清楚 action 对象的外观(例如上面)之后,您可以编写 action creator 来生成它,并编写一个 reducer 来将状态和 action 转换为下一个状态。 生成 action 的逻辑驻留在 action creator 中,对其作出反应的逻辑驻留在 reducer 中,reducer 必须是纯的。
最后,不要在状态中使用classes。它们不能按原样序列化。你不需要 Card
class。只需使用普通对象和数组。
看来最好的做法是使用静态 class 处理第一级入口点,在 redux 之外实例化 redux 操作。
我想保持商店和行动链的纯净是有意义的。
乍一看,这可能看起来像很多重复的代码,但当您开始根据条件进行调度或需要从多个地方进行调度时,它就会开始开放并变得有意义。
我在 reducer 中放入了一些逻辑,我认为应该将其放入 Action 中并传递下去?
将这类东西放在动作或减速器中是最佳实践吗?
工作示例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
}
}
我的理解是动作应该是包含两件事的简单对象:(i) 动作类型和 (ii) 改变的内容(即新数据)。
另一方面,Reducers 是纯函数,它将操作和先前的应用程序状态作为输入,return 新的应用程序状态。他们如何实现这一点取决于您。您可以添加任何必要的逻辑来结合先前的状态 + 操作和 return 新状态 只要您不在 reducer 函数之外改变数据。
具体到您的代码,我不确定 deal()
函数属于动作还是减速器。我认为更好的地方可能是某种事件处理程序(例如 onClick
)。然后,您可以将交易调用的 results 作为一个操作传递给您的减速器。
你的reducer必须是纯的。目前还不纯。它调用 deal()
调用 getRandom()
依赖于 Math.random()
因此不是纯粹的。
这种逻辑(“生成数据”,无论是随机的还是来自用户输入)应该在动作创建者中。动作创作者无需纯粹,可以放心使用Math.random()
。此操作创建者将 return 一个操作,一个描述更改的对象:
{
type: 'DEAL_CARDS',
cards: ['heart', 'club', 'heart', 'heart']
}
reducer 只会在状态中添加(或替换?)该数据。
一般来说,从一个action对象开始。它应该描述变化的方式是运行具有相同action对象和相同previous的reducer state 应该 return 相同的下一个状态。这就是为什么 reducer 不能包含 Math.random()
调用——它们会打破这个条件,因为它们每次都是随机的。您将无法测试您的减速器。
在弄清楚 action 对象的外观(例如上面)之后,您可以编写 action creator 来生成它,并编写一个 reducer 来将状态和 action 转换为下一个状态。 生成 action 的逻辑驻留在 action creator 中,对其作出反应的逻辑驻留在 reducer 中,reducer 必须是纯的。
最后,不要在状态中使用classes。它们不能按原样序列化。你不需要 Card
class。只需使用普通对象和数组。
看来最好的做法是使用静态 class 处理第一级入口点,在 redux 之外实例化 redux 操作。
我想保持商店和行动链的纯净是有意义的。
乍一看,这可能看起来像很多重复的代码,但当您开始根据条件进行调度或需要从多个地方进行调度时,它就会开始开放并变得有意义。