redux - sub - Uso correcto de reductores reductores.
redux thunk (2)
La diferencia es:
-
combineReducers
crea un estado anidado -
reduceReducers
crea estado plano
Considere los siguientes reductores. No hay tipos de acción para hacer las cosas más simples:
// this reducer adds a payload to state.sum
// and tracks total number of operations
function reducerAdd(state, payload) {
if (!state) state = { sum: 0, totalOperations: 0 }
if (!payload) return state
return {
...state,
sum: state.sum + payload,
totalOperations: state.totalOperations + 1
}
}
// this reducer multiplies state.product by payload
// and tracks total number of operations
function reducerMult(state, payload) {
if (!state) state = { product: 1, totalOperations: 0 }
if (!payload) return state
// `product` might be undefined because of
// small caveat in `reduceReducers`, see below
const prev = state.product || 1
return {
...state,
product: prev * payload,
totalOperations: state.totalOperations + 1
}
}
CombinarReductores
Cada reductor obtiene un estado independiente (consulte también http://redux.js.org/docs/api/combineReducers.html ):
const rootReducer = combineReducers({
add: reducerAdd,
mult: reducerMult
})
const initialState = rootReducer(undefined)
/*
* {
* add: { sum: 0, totalOperations: 0 },
* mult: { product: 1, totalOperations: 0 },
* }
*/
const first = rootReducer(initialState, 4)
/*
* {
* add: { sum: 4, totalOperations: 1 },
* mult: { product: 4, totalOperations: 1 },
* }
*/
// This isn''t interesting, let''s look at second call...
const second = rootReducer(first, 4)
/*
* {
* add: { sum: 8, totalOperations: 2 },
* mult: { product: 16, totalOperations: 2 },
* }
*/
// Now it''s obvious, that both reducers get their own
// piece of state to work with
reducirReductores
Todos los reductores comparten el mismo estado.
const addAndMult = reducerReduce(reducerAdd, reducerMult)
const initial = addAndMult(undefined)
/*
* {
* sum: 0,
* totalOperations: 0
* }
*
* First, reducerAdd is called, which gives us initial state { sum: 0 }
* Second, reducerMult is called, which doesn''t have payload, so it
* just returns state unchanged.
* That''s why there isn''t any `product` prop.
*/
const next = addAndMult(initial, 4)
/*
* {
* sum: 4,
* product: 4,
* totalOperations: 2
* }
*
* First, reducerAdd is called, which changes `sum` = 0 + 4 = 4
* Second, reducerMult is called, which changes `product` = 1 * 4 = 4
* Both reducers modify `totalOperations`
*/
const final = addAndMult(next, 4)
/*
* {
* sum: 8,
* product: 16,
* totalOperations: 4
* }
*/
Casos de uso
-
combineReducers
: cada reductor administra su propia porción de estado (por ejemplo,state.todos
ystate.logging
). Esto es útil cuando se crea un reductor de raíz . -
reduceReducers
: cada reductor gestiona el mismo estado. Esto es útil cuando se encadenan varios reductores que se supone que operan en el mismo estado (esto podría suceder, por ejemplo, cuando se combinan varios reductores creados utilizandohandleAction
de redux-actions )
La diferencia es obvia a partir de la forma del estado final.
Advertencias
Hay una pequeña advertencia en reduceReducers
: cuando se llama al reductor final con state = undefined
, debe devolver el estado inicial. Sin embargo, solo el primer reductor en la cadena queda undefined
, todos los demás reductores recibirán el estado desde el primero.
No entiendo para qué se reduce-reducers . ¿Se utilizará en caso de que tenga 2 funciones reductoras que contengan la misma acción?
function reducerA(state, action){
switch(action.type):
...
case ''SAME_ACTION'': {...state, field: state.field+1}
}
function reducerB(state, action){
switch(action.type):
...
case ''SAME_ACTION'': {...state, field: state.field*2}
}
Por lo tanto, si reduceReducer
a reduceReducer
on reducerA
y reducerA
y se reducerB
acción ''SAME_ACTION'' para {field: 0}
entonces tendré el siguiente estado {field: 2}
?
También me parece que concatena los reductores (es decir, fusionándolos en una sola tecla).
¿Tengo razón o reduceReducer
tiene un propósito diferente?
Tampoco entiendo qué reductores está tratando de resolver. El caso de uso descrito por @ Tomáš se puede lograr con un simple Reductor. Después de todo, Reducer es solo una función que acepta el estado de la aplicación y una acción, y devuelve un objeto que contiene el nuevo estado de la aplicación. Por ejemplo, puede hacer lo siguiente en lugar de usar los Reductores combinados provistos por redux:
import combinationReducer from "./combinationReducer";
import endOfPlayReducer from "./endOfPlayReducer";
import feedbackReducer from "./feedbackReducer";
function combineReducers(appState, action) {
return {
combination: combinationReducer(appState, action),
feedbacks: feedbackReducer(appState, action),
endOfPlay: endOfPlayReducer(appState, action)
};
}
Y, por supuesto, aquí, sus reductores aceptan todo el estado de la aplicación y devuelven solo la porción de la que son responsables. Una vez más, es solo una función, puedes personalizarla como quieras. Puedes leer más sobre esto here