javascript - style - title label html
¿Por qué un reductor Redux se llama reductor? (5)
La razón por la que un reductor de redux se denomina
reducer
es porque se podría "reducir" unacollection of actions
y uninitial state
(de la tienda) en el que realizar estas acciones para obtener elfinal state
resultante.
¿Cómo? Para responder a eso, déjame definir un reductor de nuevo:
El método reduce() aplica una
function (reducer)
contra unaccumulator
y cada valor de la matriz (de izquierda a derecha) para reducirlo a un solo valor.
¿Y qué hace un redux reductor?
El reductor es una
function
pura que toma el estado actual y una acción, y devuelve el siguiente estado. Tenga en cuenta que el estado seaccumulated
medida que cada acción en la colección se aplica para cambiar este estado.
Por lo tanto, dada una collection of actions
, el reductor se aplica a cada valor de la colección (de izquierda a derecha). La primera vez, devuelve el initial value
. Ahora el reductor se aplica nuevamente en este estado inicial y la primera acción para devolver el estado siguiente. Y el siguiente elemento de colección (acción) se aplica cada vez en el current state
para obtener el next state
hasta que llegue al final de la matriz. Y luego, obtienes the final state
. ¡Cuan genial es eso!
Mientras aprendía Redux
me he encontrado con Reducers
. La documentación establece:
El reductor es una función pura que toma el estado anterior y una acción, y devuelve el siguiente estado. (previousState, action) => newState. Se llama reductor porque es el tipo de función que pasaría a Array.prototype.reduce (reductor,? InitialValue).
MDN describe el método de reduce
como:
El método reduce () aplica una función contra un acumulador y cada valor de la matriz (de izquierda a derecha) para reducirla a un solo valor.
Todavía estoy confundido sobre por qué la definición Redux de un reductor, ya que no tiene sentido. En segundo lugar, la descripción de MDN tampoco parece correcta. El método de reduce
no siempre se utiliza para reducir a un solo valor. Se puede usar en lugar del map
y el filter
y en realidad es más rápido cuando se usa en lugar del encadenamiento.
¿Es incorrecta la descripción de MDN?
Saltando de nuevo a la definición de Redux de un reductor, dice:
Se llama reductor porque es el tipo de función que pasaría a Array.prototype.reduce (reductor,? InitialValue)
Tengo la impresión de que un reductor en Redux es responsable de modificar el estado. Un reductor de ejemplo:
const count = function(state, action) {
if(action.type == ''INCREMENT'') {
return state + 1;
} else if(action.type == ''DECREMENT'') {
return state - 1;
} else {
return state;
}
}
... No veo cómo esta es una función que se pasaría a reduce
. ¿Cómo se reducen esos datos a un solo valor? Si esta es una función que pasaría a reduce
entonces el state
sería la devolución de llamada y la action
sería el valor inicial.
Gracias por cualquier explicación clara. Es difícil de conceptualizar.
Se llama reductor porque es el tipo de función que pasaría a Array.prototype.reduce (reductor,? InitialValue)
Esto es muy similar a lo que pasaría a Array.reduce como la devolución de llamada (reductor). La parte importante es:
callback
Function to execute on each value in the array, taking four arguments:
previousValue
The value previously returned in the last invocation of the callback, or initialValue, if supplied. (See below.)
currentValue
The current element being processed in the array.
Donde estado es el "valor previo" y acción es el "valor actual".
Tengo la impresión de que un reductor en Redux es responsable de modificar el estado. Un reductor de ejemplo:
const count = function(state, action) {
if (action.type == ''INCREMENT'') {
return state + 1;
} else if (action.type == ''DECREMENT'') {
return state - 1;
} else {
return state;
}
}
... No veo cómo esta es una función que se pasaría a reducir. ¿Cómo se reducen esos datos a un solo valor? Si esta es una función que pasaría a reducir, entonces el estado sería la devolución de llamada y la acción sería el valor inicial.
// count function from your question
const count = function (state, action) {
if (action.type == ''INCREMENT'') {
return state + 1;
} else if (action.type == ''DECREMENT'') {
return state - 1;
} else {
return state;
}
}
// an array of actions
const actions =
[ { type: ''INCREMENT'' }
, { type: ''INCREMENT'' }
, { type: ''INCREMENT'' }
, { type: ''INCREMENT'' }
, { type: ''DECREMENT'' }
]
// initial state
const init = 0
console.log(actions.reduce(count, init))
// 3 (final state)
// (INCREMENT 4 times, DECREMENT 1 time)
El término "reducir" es en realidad un término funcional utilizado en la programación funcional. En un lenguaje como Haskell, F #, o incluso JavaScript, definimos una transformación que toma una colección (de cualquier tamaño) como entrada y devuelve un solo valor como salida.
Así que (no ser pedante, pero me parece que esto me ayuda) pensar en ello visualmente. Tenemos una colección:
[][][][][][][][][][]
... que queremos colapsar en un solo valor.
N
Programando funcionalmente, haríamos esto con una sola función que podríamos llamar recursivamente en cada elemento de la colección. Pero si haces eso, necesitas hacer un seguimiento del valor intermedio en algún lugar, ¿verdad? Las implementaciones no puras pueden mantener algún tipo de "acumulador" o variable fuera de la función para realizar un seguimiento del estado, de esta manera:
var accumulator = 0;
var myArray = [1,2,3,4,5];
myArray.reduce(function (each) {
accumulator += 0;
});
return accumulator;
Sin embargo, con las funciones puras, no podemos hacer esto, porque, por definición, las funciones puras no pueden tener efectos fuera de su alcance de función. En lugar de confiar en una variable externa que encapsula nuestro "estado" entre las llamadas, simplemente pasamos el estado en el método.
var myArray = [1,2,3,4,5];
return myArray.reduce(function (accumulator, each) {
return accumulator + each;
}, 0);
En este caso, llamamos a la función "reductor" debido a su firma de método. Tenemos each
(o current
- cualquier nombre está bien), que representa un objeto en la colección; y el state
(o previous
), que se pasa a cada iteración de la función, que representa los resultados de la transformación que ya hemos hecho a los elementos anteriores en la colección.
Tenga en cuenta que la documentación de MDN a la que hace referencia es correcta; La función reduce()
siempre devuelve un solo valor. De hecho, el método de reduce
en cualquier idioma es una función de orden superior que toma un "reductor" (una función con la firma del método definida anteriormente) y devuelve un solo valor. Ahora, sí, puedes hacer otras cosas con él, si tu función que llamas tiene efectos secundarios, pero no deberías. (Esencialmente, no use .reduce()
como foreach). Incluso si el método al que llama con reduce
tiene efectos secundarios, el valor de retorno de reduce será un valor único, no una recopilación.
Lo bueno de esto es que este patrón no solo tiene que aplicarse a matrices o colecciones concretas, como has visto en React; Este patrón también se puede aplicar a los flujos, ya que son funciones puras.
Espero que esto ayude. Por lo que vale la pena, la definición en el sitio de Redux podría mejorarse (ya que el concepto de reductor no se debe solo al método prototipo Array de Javascript). Usted debe enviar un PR!
Edición: Hay un artículo de Wikipedia sobre el tema. Tenga en cuenta que reduce tiene diferentes nombres, y en los lenguajes funcionales, se conoce comúnmente como Fold. https://en.wikipedia.org/wiki/Fold_(higher-order_function)#Folds_as_structural_transformations
Lo siento, pero no estaría de acuerdo con las respuestas anteriores. Yo no apoyaría el reducer
nombres. Me apasiona la FP y la inmutabilidad. No me culpes, lee la segunda parte, pero primero quiero decir por qué no estoy de acuerdo.
Es correcto que los reductores son la secuencia de transformaciones, pero la secuencia en sí misma podría ser parte de otra secuencia. Imagínalo, como enlaces - una parte de la cadena. Pero la cadena misma podría ser parte de una cadena más larga. Cada enlace es la "transición" del estado global. Que, ¿cuál es la teoría detrás de esto?
¿No es en realidad la "máquina de estados finitos"? - cerca, pero no. En realidad es el sistema de transición .
Un sistema de transición etiquetado es una tupla (S, Λ, →) donde S es un conjunto de estados, Λ es un conjunto de etiquetas y → es un conjunto de transiciones etiquetadas
Por lo tanto, S
- se establecen de nuestros estados
Λ
- son nuestras llamadas "acciones" (pero las etiquetas en teoría)
... y
→
- reductores "transiciones etiquetadas"! Yo lo llamaría así, si soy el creador de esta biblioteca.
Comprender esta teoría me ayudó a implementar mi biblioteca, donde puedo tener un sistema de transición de bajo nivel como parte del sistema de transición de alto nivel (como una cadena, aún podría ser parte de una cadena más larga) y aún tener un único estado de Redux global.