Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Uso de combineReducers
Conceptos Fundamentales
La estructura de estado más común en una aplicación Redux es un objeto plano de JavaScript que contiene "segmentos" de datos específicos de dominio en cada clave de nivel superior. De manera similar, el enfoque más común para escribir la lógica de reductores para esa estructura es tener funciones "reductoras de segmento", cada una con la misma firma (state, action), siendo cada una responsable de gestionar todas las actualizaciones de su segmento específico del estado. Múltiples reductores de segmento pueden responder a la misma acción, actualizar su propio segmento de forma independiente según sea necesario, y los segmentos actualizados se combinan en el nuevo objeto de estado.
Dado que este patrón es tan común, Redux proporciona la utilidad combineReducers para implementar ese comportamiento. Es un ejemplo de un reductor de orden superior que toma un objeto lleno de funciones reductoras de segmento y devuelve una nueva función reductora.
Hay varias ideas importantes a considerar al usar combineReducers:
-
Primero y principal,
combineReducerses simplemente una función de utilidad para simplificar el caso de uso más común al escribir reductores Redux. No estás obligado a usarla en tu aplicación, y no maneja todos los escenarios posibles. Es perfectamente posible escribir lógica de reductores sin usarla, y es bastante común necesitar escribir lógica de reductores personalizada para casos quecombineReducerno maneja. (Consulta Más allá decombineReducerspara ver ejemplos y sugerencias.) -
Mientras que Redux en sí mismo no es dogmático sobre cómo organizas tu estado,
combineReducersimpone varias reglas para ayudar a los usuarios a evitar errores comunes. (ConsultacombineReducerspara más detalles.) -
Una pregunta frecuente es si Redux "llama a todos los reductores" al despachar una acción. Como realmente solo hay una función reductora raíz, la respuesta predeterminada es "no, no lo hace". Sin embargo,
combineReducerstiene un comportamiento específico que sí funciona de esa manera. Para ensamblar el nuevo árbol de estado,combineReducersllamará a cada reductor de segmento con su porción actual del estado y la acción actual, dando al reductor de segmento la oportunidad de responder y actualizar su porción de estado si es necesario. Así que, en ese sentido, usarcombineReducerssí "llama a todos los reductores", o al menos a todos los reductores de segmento que está envolviendo. -
Puedes usarlo en todos los niveles de tu estructura de reductores, no solo para crear el reductor raíz. Es muy común tener múltiples reductores combinados en varios lugares, que se componen juntos para crear el reductor raíz.
Definiendo la Forma del Estado
Hay dos formas de definir la forma y contenido inicial del estado de tu store. Primero, la función createStore puede tomar preloadedState como segundo argumento. Esto está destinado principalmente a inicializar el store con un estado persistido previamente en otro lugar, como el localStorage del navegador. La otra forma es que el reductor raíz devuelva el valor de estado inicial cuando el argumento de estado es undefined. Estos dos enfoques se describen con más detalle en Inicialización del Estado, pero hay consideraciones adicionales al usar combineReducers.
combineReducers toma un objeto lleno de funciones reductoras de segmento y crea una función que produce un objeto de estado correspondiente con las mismas claves. Esto significa que si no se proporciona un estado precargado a createStore, la nomenclatura de las claves en el objeto de reductores de segmento definirá las claves en el objeto de estado resultante. La correlación entre estos nombres no siempre es evidente, especialmente cuando se usan características como exportaciones de módulos por defecto y abreviaturas de objetos literales.
Aquí un ejemplo de cómo el uso de abreviaturas de objetos literales con combineReducers puede definir la forma del estado:
// reducers.js
export default theDefaultReducer = (state = 0, action) => state
export const firstNamedReducer = (state = 1, action) => state
export const secondNamedReducer = (state = 2, action) => state
// rootReducer.js
import { combineReducers, createStore } from 'redux'
import theDefaultReducer, {
firstNamedReducer,
secondNamedReducer
} from './reducers'
// Use object literal shorthand syntax to define the object shape
const rootReducer = combineReducers({
theDefaultReducer,
firstNamedReducer,
secondNamedReducer
})
const store = createStore(rootReducer)
console.log(store.getState())
// {theDefaultReducer : 0, firstNamedReducer : 1, secondNamedReducer : 2}
Observa que al usar la abreviatura para definir un objeto literal, los nombres de las claves en el estado resultante son los mismos que los nombres de las variables importadas. Esto puede no ser siempre el comportamiento deseado, y a menudo causa confusión para quienes no están familiarizados con la sintaxis moderna de JavaScript.
Además, los nombres resultantes son un poco extraños. Por lo general, no es una buena práctica incluir palabras como "reducer" en los nombres de las claves de tu estado; las claves deberían simplemente reflejar el dominio o tipo de datos que contienen. Esto significa que debemos especificar explícitamente los nombres de las claves en el objeto del reducer de porción para definir las claves en el objeto de estado resultante, o renombrar cuidadosamente las variables de los reducers de porción importados para configurar las claves cuando usamos la sintaxis abreviada de objeto literal.
Un uso mejor sería el siguiente:
import { combineReducers, createStore } from 'redux'
// Rename the default import to whatever name we want. We can also rename a named import.
import defaultState, {
firstNamedReducer,
secondNamedReducer as secondState
} from './reducers'
const rootReducer = combineReducers({
defaultState, // key name same as the carefully renamed default export
firstState: firstNamedReducer, // specific key name instead of the variable name
secondState // key name same as the carefully renamed named export
})
const reducerInitializedStore = createStore(rootReducer)
console.log(reducerInitializedStore.getState())
// {defaultState : 0, firstState : 1, secondState : 2}
Esta estructura del estado refleja mejor los datos involucrados, porque nos aseguramos de configurar las claves que pasamos a combineReducers.