reactjs - significado - Reducir un subárbol completo con redux combineReducers
redux significado (2)
Tengo un árbol reductor que se ve así:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: combineReducers({
sets,
boosters
}),
servers: combineReducers({
servers
})
})
});
Ahora la clave de setup
contiene un formulario que debe restablecerse una vez que lo hayamos enviado. Sin embargo, no tengo forma de acceder a todo setup
árbol de setup
porque usar combineReducers significa que los reductores solo manipulan los datos en los nodos hoja del árbol ( sets
y boosters
en este caso).
Mi primer impulso es hacer una función que reduzca todo el árbol de configuración de esta manera:
function setup(state, action){
//If there''s an action that affects this whole tree, handle it
switch(action.type){
case "FORM_SUBMIT": //DO STUFF
break;
}
//Otherwise just let the reducers care about their own data
return combineReducers({
sets,
boosters
})(state);
}
Pero eso no funciona, y también arruina la estructura de árbol agradable de mi primer ejemplo de código.
¿Hay una mejor solución para esto con redux?
la respuesta de @acjay es una gran idea! Solo quería usar el antiguo método reducer(state, action)
y no una función de orden superior. Así que creé un método que compone el reductor en una relación maestro-esclavo.
Maestro-esclavo
export default function masterSlaveReducer(reducerMaster, reducerSlave) {
return (state, action) => {
const newState = reducerMaster(state, action);
if(newState === state){
return reducerSlave(state, action);
}
return newState;
};
}
El código de Miguel se usaría de esta manera:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: masterSlaveReducer(
setup, // setup() from Miguel''s question
combineReducers({
sets,
boosters
})
),
servers: combineReducers({
servers
})
})
});
combineReducers
es un patrón agradable, ya que tiende a imponer la idea de que los reductores deben ubicarse en subconjuntos no superpuestos de la tienda, desacoplados de la estructura de la tienda. Toma la opinión de que debes reducir las hojas, no las ramas, y maneja la reducción de las ramas.
Dicho esto, puede haber buenas razones para usar un patrón alternativo. Como mencioné en una pregunta ligeramente relacionada , puedes optar por no usar puramente los combineReducers
y descomponer tus reductores como mejor te parezca.
En tu caso, podrías decorar tu combineReducers
interior.
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: setupReducer(
combineReducers({
sets,
boosters
})
),
servers: combineReducers({
servers
})
})
});
Aquí, setupReducer
es una función de orden superior . Esto puede ser complicado de razonar, pero así es cómo lo abordo:
- Sabemos que
setupReducer
toma un reductor como argumento, porque estamos pasando el resultado decombineReducers
a él. - Sabemos que la firma del reductor devuelto por
combineReducers
es(state, action) => state
. - También sabemos que
setupReducer
tiene que devolver un reductor, que, de nuevo, es una función de la firma(state, action) => state
.
En otras palabras, toma un reductor y devuelve un reductor: ((state, action) => state) => ((state, action) => state)
. Por lo tanto, podría verse así:
function setupReducer(subReducer) {
return (state, action) => {
//If there''s an action that affects this whole tree, handle it
switch(action.type){
case "FORM_SUBMIT":
// ... create newState
return newState;
default:
return subReducer(state, action);
}
}
}
Mantuve su flujo lógico arriba, pero como punto de precaución, puede llamar subReducer
incondicionalmente y luego modificar su salida. De lo contrario, tendrá que asegurarse de que las ramas donde no se llama siempre produzcan un objeto de la misma forma, lo que parece ser un punto de acoplamiento adhesivo.