为什么Redux的状态函数称为reducers?


82

这是Redux官方文档的一部分

之所以称为简化器,是因为它是传递给函数的类型 Array.prototype.reduce(reducer, ?initialValue)

这对我来说没有多大意义。有人可以向我解释为什么它们实际上称为减速器吗?它们返回默认值(或具有默认参数值)的事实并不会使它们归约。


6
它们之所以成为简化器,是因为它们的行为类似于您传递给的函数reduce,该函数可以访问默认值和另一个值,并为您提供可能转换后的默认值。state -> action -> state
azium

2
一朵玫瑰花,可能是行销的;map / reduce现在成了流行语……
dandavis

1
这就是为什么您必须开始思考自己而不依赖框架的原因。框架主要是一个或几个开发人员的工作,他们具有解决互联网用户适应问题的自己的见解。一些框架正确无误,但大多数情况下是不正确的。一吻之吻,解决不了多少。这只是许多例子。
Codebeat

Answers:


71

它们返回默认值(或具有默认参数值)的事实并不会使它们归约。

减速器不仅仅返回默认值。它们总是返回状态的累积(基于所有先前和当前的动作)。

因此,它们充当状态的减少者。每次调用redux reducer时,都会通过action传递状态(state, action)。然后,根据操作减少(或累积)该状态,然后返回下一个状态。这是经典foldreduce功能的一个循环。

正如@azium总结的那样state -> action -> state


7
根据这个逻辑,Humm难道不应该将它们称为增加器而不是减少器吗?没有数据被减少,它被添加了:/大声笑
Jamie Hutber'6

16
@JamieHutber我认为您在这种情况下会稍微怀念reducer的含义。reducer正在获取项目流(或集合)并将它们组合为一个项目。在这种情况下,所有操作(通过时间)都是项目的集合,状态是单个项目。有道理?
戴文·崔顿

7
大声笑我现在看到了。因此,基本上只是将它们概括出来。为什么不称其为合并,那么:P表示感谢:)
Jamie Hutber

20
谢天谢地,我并不是唯一一个认为减速器这个名称在我撰写本文时至少有2,000次浏览量的人。有人甚至愿意花更多的精力来挖掘为什么被称为减速器的事实,这并不意味着它确实有些偏离吗?如果因为它是传递给Array.prototype.reduce的函数类型而被称为reducer,那就像让我们将Orange称为榨汁机是因为我们将orange传递给object.prototype.juicer还是不应该将它称为Fruit?
伊尼

2
我同意,这根本不是一个直观的名称。从逻辑上讲,被称为reducer的它应该减少一些东西。如果将状态更改与状态一起放在整个阵列中,然后一次将它们组合成一个状态,那么它将是一个直观的名称。
Peter Evan Deal

20

如果您将应用程序中的一系列操作视为列表,或者更像是流,则可能更有意义。

举这个人为的例子:

['apple', 'banana', 'cherry'].reduce((acc, item) => acc + item.length, 0)

第一个参数是形式的函数(Int, String) => Int。连同初始值一起,传递reduce可能称为“归约函数”的值,并获得处理一系列项目的结果。因此,您可能会说,化简函数描述了如何对每个连续的单独项目进行更改以更改结果。换句话说,reducer函数获取先前的输出和下一个值,并计算下一个输出。

这类似于Redux reducer的操作:它采用上一个状态和当前操作,并计算下一个状态。

在真正的函数式编程风格中,您可以从概念上消除应用于自变量和结果的含义,而只关注输入和输出的“形状”。

在实践中,Redux减速器通常是正交的,这意味着对于给定的动作,它们都不会全部更改相同的属性,这使得轻松划分职责并使用汇总输出combineReducers


是的,您是对的,当我考虑更像流的操作时,这更有意义。太酷了!
Anton Savchenko

这是我最初的理解方式,但是到目前为止,这似乎并不是我所见过的任何商店实现方式都实现的方式……
Boris Callens

16

如前所述,该名称与函数式编程中的reducer概念相关。您可能还会发现Merriam-Webster词典对reducer的定义很有用:

1a。聚集在一起或促使融合:合并(将所有问题简化为一个)

减速器将动作合并为一个代表应用程序状态的对象。


8

之所以将redux reducer称为areducer是因为您可以“减少” (商店中的)acollection of actions和an initial state,以便在其上执行这些操作以获得结果final state

怎么样?为了回答这个问题,让我再次定义一个减速器:

减少()方法施加function (reducer)针对accumulator与阵列的每个值(从左到右),以将其降低到一个值。

Redux减速器有什么作用?

减速器是function采用当前状态和操作并返回下一个状态的纯函数。请注意,状态是accumulated应用集合上的每个操作来更改此状态的状态。

因此,给定a collection of actions,将缩减器应用于集合的每个值(从左到右)。第一次返回initial value。现在,将reducer再次应用于此初始状态和返回下一个状态的第一个操作。每次都会在上应用下一个收集项(操作)current state以获取next state直到到达数组末尾。然后,您得到the final state。多么酷啊!


5

作者认为状态是reduce函数的累加器。例如:

Final State = [Action1, Action2, ..., ActionN].reduce(reducer, Initial State);

reduce函数来自Functional Programming,名称“ reducer”也来自FP。

我不喜欢在这里使用这个名字。因为我不认为世界是行动后的单一价值结果。这里的状态是一个对象。例如:

['eat', 'sleep'] === [addTodo('eat'), addTodo('sleep')].reduce(reducer, []);

减速器完全不减少任何东西。而且我不在乎它是否会减少任何东西。将其命名为Transducer会更有意义。


5

我们知道减速器来自何处(函数式编程),以及为什么可以将它们视为减少工作量(将n个输入项减少为单个返回值-这就是正常功能所支持的)。但是:名称只是一个名称,就像rose是玫瑰的名字一样。不要想太多。Redux程序员是IT人员,他们被锁定在上下文中,这很有意义。我们其余的人必须接受发明人的权利,将蓝狗称为黄猫;-)



1

他们不应该称为减少作为减少手段,减少,这些功能通常使更多。然后返回


1

我不太清楚Redux缩减器如何直接映射到您使用的函数reduce,因此这里有一些示例来说明它们如何匹配。

首先是MDN Array.reduce文档中的标准reducer(在MDN中称为“累加器”)功能,然后是Dan AbramovCounter.js“您可能不需要Redux”博客文章末尾的简化示例。

  • sum 向累加器添加一个值
  • reducer 向累加器添加/减去一个值。

在这两种情况下,“状态”都只是一个整数。

您正在将操作“累积”到状态中。这也是修改任何JavaScript对象的不变方法。

const sum = function(acc, val) {
    return acc + val;
};

const reducer = function(state, action) {
    switch (action) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
};

console.log('sum', [1, -1, 1].reduce(sum, 0));

console.log('reduce', ['INCREMENT', 'DECREMENT', 'INCREMENT'].reduce(reducer, 0));

console.log('sum', [1, 1, 1].reduce(sum, 0));

console.log('reduce', ['INCREMENT', 'INCREMENT', 'INCREMENT'].reduce(reducer, 0));


0

其他答案很好地解释了为何如此命名,但让我们尝试命名更多内容...

const origState = 0;
const actionOperators = {
    increment: (origState) => origState++,
    decrement: (origState) => origState--,
};
const anOperator = (aState, anAction) => actionOperators[anAction](aState);
const actions = ['increment', 'decrement', 'increment'];
const finalState = actions.reduce(anOperator, origState);

首先,reduce可以称为use anOperator with every action name and accumulated state, starting with origState。在Smalltalk中,它称为actions inject: origState into: anOperator。但是您实际上向操作员注入了什么?origState和操作名称。因此,即使在Smalltalk中,方法名称也不是很清楚。

actionOperators[increment]是Reducer,但我宁愿将其称为actionOperator,因为它是为每个操作实现的。状态只是一个参数(另一个是返回值)。

然而,Reducer是在Google搜索结果之上的一个更好的词。它也与Redux类似。


0

在下面的这段代码中,您只需要将累加器视为动作,并将currentValue视为redux上下文中的状态。在此示例中,您将找到为什么他们也将其命名为减速器。

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// Main operation is 1 + 2 + 3 + 4 = 10
// but think of it as a stack like this: 

// | 2 | | 3 | | 4 | 
// |_1_| |_3_| |_6_| | 10 | => the 10 is in result

console.log(array1.reduce(reducer));
// expected output: 10

reduce()方法在数组的每个元素上执行reducer函数(由您提供),从而产生单个输出值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.