Fundamentos de Redux, Parte 4: Almacén
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
- Cómo crear un almacén de Redux
- Cómo usar el almacén para actualizar el estado y escuchar cambios
- Cómo configurar el almacén para extender sus capacidades
- Cómo configurar la Redux DevTools Extension para depurar tu aplicación
Introducción
En Parte 3: Estado, Acciones y Reductores, comenzamos a escribir nuestra aplicación de ejemplo de tareas. Listamos los requisitos del negocio, definimos la estructura del estado necesaria para que la aplicación funcione, y creamos una serie de tipos de acción para describir "qué sucedió" y que coincidan con los tipos de eventos que pueden ocurrir cuando un usuario interactúa con nuestra aplicación. También escribimos funciones reductoras que pueden manejar la actualización de nuestras secciones state.todos y state.filters, y vimos cómo podemos usar la función combineReducers de Redux para crear un "reductor raíz" basado en los diferentes "reductores por segmento" para cada funcionalidad de nuestra aplicación.
Ahora es momento de unir estas piezas con el elemento central de una aplicación Redux: el almacén.
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Ten en cuenta que este tutorial muestra intencionadamente patrones de lógica de Redux de estilo antiguo que requieren más código que los patrones de "modern Redux" con Redux Toolkit que enseñamos como el enfoque correcto para construir aplicaciones con Redux hoy en día, con el fin de explicar los principios y conceptos detrás de Redux. No está pensado para ser un proyecto listo para producción.
Consulta estas páginas para aprender a usar "modern Redux" con Redux Toolkit:
- El tutorial completo de "Redux Essentials", que enseña "cómo usar Redux, de la manera correcta" con Redux Toolkit para aplicaciones del mundo real. ¡Recomendamos que todos los aprendices de Redux lean el tutorial "Essentials"!
- Redux Fundamentals, Parte 8: Modern Redux con Redux Toolkit, que muestra cómo convertir los ejemplos de bajo nivel de secciones anteriores en equivalentes modernos de Redux Toolkit
Almacén de Redux
El almacén de Redux reúne el estado, las acciones y los reductores que componen tu aplicación. El almacén tiene varias responsabilidades:
-
Contiene el estado actual de la aplicación en su interior
-
Permite acceder al estado actual mediante
store.getState(); -
Permite actualizar el estado mediante
store.dispatch(action); -
Registra funciones callback de escucha mediante
store.subscribe(listener); -
Maneja la cancelación de suscripciones mediante la función
unsubscribedevuelta porstore.subscribe(listener).
Es importante destacar que solo tendrás un único almacén en una aplicación Redux. Cuando quieras dividir tu lógica de manejo de datos, usarás composición de reductores y crearás múltiples reductores que puedan combinarse, en lugar de crear almacenes separados.
Creación de un almacén
Cada almacén de Redux tiene una única función reductor raíz. En la sección anterior, creamos una función reductor raíz usando combineReducers. Ese reductor raíz está actualmente definido en src/reducer.js en nuestra aplicación de ejemplo. Importemos ese reductor raíz y creemos nuestro primer almacén.
La biblioteca principal de Redux tiene una API createStore que creará el almacén. Añade un nuevo archivo llamado store.js, importa createStore y el reductor raíz. Luego, llama a createStore y pasa el reductor raíz:
import { createStore } from 'redux'
import rootReducer from './reducer'
const store = createStore(rootReducer)
export default store
Carga del estado inicial
createStore también puede aceptar un valor preloadedState como segundo argumento. Puedes usar esto para añadir datos iniciales cuando se crea el almacén, como valores incluidos en una página HTML enviada desde el servidor, o persistidos en localStorage y recuperados cuando el usuario vuelve a visitar la página, así:
import { createStore } from 'redux'
import rootReducer from './reducer'
let preloadedState
const persistedTodosString = localStorage.getItem('todos')
if (persistedTodosString) {
preloadedState = {
todos: JSON.parse(persistedTodosString)
}
}
const store = createStore(rootReducer, preloadedState)
Despacho de acciones
¡Ahora que hemos creado un almacén, verifiquemos que nuestro programa funciona! Incluso sin interfaz de usuario, ya podemos probar la lógica de actualización.
Antes de ejecutar este código, intenta volver a src/features/todos/todosSlice.js y elimina todos los objetos de tareas de ejemplo del initialState para que sea un array vacío. Eso hará que la salida de este ejemplo sea más fácil de leer.
// Omit existing React imports
import store from './store'
// Log the initial state
console.log('Initial state: ', store.getState())
// {todos: [....], filters: {status, colors}}
// Every time the state changes, log it
// Note that subscribe() returns a function for unregistering the listener
const unsubscribe = store.subscribe(() =>
console.log('State after dispatch: ', store.getState())
)
// Now, dispatch some actions
store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about actions' })
store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about reducers' })
store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about stores' })
store.dispatch({ type: 'todos/todoToggled', payload: 0 })
store.dispatch({ type: 'todos/todoToggled', payload: 1 })
store.dispatch({ type: 'filters/statusFilterChanged', payload: 'Active' })
store.dispatch({
type: 'filters/colorFilterChanged',
payload: { color: 'red', changeType: 'added' }
})
// Stop listening to state updates
unsubscribe()
// Dispatch one more action to see what happens
store.dispatch({ type: 'todos/todoAdded', payload: 'Try creating a store' })
// Omit existing React rendering logic
Recuerda que cada vez que llamamos a store.dispatch(action):
-
El almacén llama a
rootReducer(state, action)- Ese reducer raíz puede invocar otros reducers de slice internamente, como
todosReducer(state.todos, action)
- Ese reducer raíz puede invocar otros reducers de slice internamente, como
-
El almacén guarda el valor del estado nuevo internamente
-
El almacén llama a todas las funciones callback de suscripción de listeners
-
Si un listener tiene acceso al
store, ahora puede llamar astore.getState()para leer el último valor del estado
Si observamos la salida del registro en la consola de ese ejemplo, puedes ver cómo cambia el estado de Redux al despachar cada acción:

Observa que nuestra aplicación no registró nada de la última acción. Esto se debe a que eliminamos el callback del listener al llamar a unsubscribe(), así que nada más se ejecutó después de despachar la acción.
Especificamos el comportamiento de nuestra aplicación incluso antes de empezar a escribir la interfaz de usuario. Esto ayuda a darnos confianza en que la aplicación funcionará como se espera.
Si lo deseas, ahora puedes intentar escribir pruebas para tus reducers. Como son funciones puras, debería ser sencillo probarlos. Llámalos con un state y action de ejemplo, toma el resultado y verifica si coincide con lo que esperas:
import todosReducer from './todosSlice'
test('Toggles a todo based on id', () => {
const initialState = [{ id: 0, text: 'Test text', completed: false }]
const action = { type: 'todos/todoToggled', payload: 0 }
const result = todosReducer(initialState, action)
expect(result[0].completed).toBe(true)
})
Dentro de un almacén de Redux
Puede ser útil echar un vistazo dentro de un almacén de Redux para entender cómo funciona. Aquí tienes un ejemplo minimalista de un almacén de Redux funcional, en unas 25 líneas de código:
function createStore(reducer, preloadedState) {
let state = preloadedState
const listeners = []
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener)
return function unsubscribe() {
const index = listeners.indexOf(listener)
listeners.splice(index, 1)
}
}
function dispatch(action) {
state = reducer(state, action)
listeners.forEach(listener => listener())
}
dispatch({ type: '@@redux/INIT' })
return { dispatch, subscribe, getState }
}
Esta versión reducida de un almacén de Redux funciona lo suficientemente bien como para reemplazar la función real createStore de Redux que has estado usando en tu aplicación hasta ahora. (¡Pruébalo y compruébalo tú mismo!) La implementación real del almacén de Redux es más extensa y un poco más compleja, pero la mayor parte son comentarios, mensajes de advertencia y manejo de casos extremos.
Como puedes ver, la lógica real aquí es bastante breve:
-
El almacén tiene el valor actual de
statey la funciónreducerinternamente -
getStatedevuelve el valor actual del estado -
subscribemantiene un array de callbacks de listeners y devuelve una función para eliminar el nuevo callback -
dispatchllama al reducer, guarda el estado y ejecuta los listeners -
El almacén despacha una acción al inicio para inicializar los reducers con su estado
-
La API del almacén es un objeto con
{dispatch, subscribe, getState}internamente
Para enfatizar uno de estos puntos en particular: observa que getState simplemente devuelve cualquier valor actual que tenga state. Esto significa que ¡por defecto, nada te impide mutar accidentalmente el valor del estado actual! Este código se ejecutará sin errores, pero es incorrecto:
const state = store.getState()
// ❌ Don't do this - it mutates the current state!
state.filters.status = 'Active'
En otras palabras:
-
El almacén de Redux no hace una copia adicional del valor
statecuando llamas agetState(). Es exactamente la misma referencia que devolvió la función root reducer -
El almacén de Redux no hace nada más para prevenir mutaciones accidentales. Es posible mutar el estado, ya sea dentro de un reducer o fuera del almacén, y siempre debes tener cuidado para evitar mutaciones.
Una causa común de mutaciones accidentales es la ordenación de arrays. Llamar a array.sort() realmente muta el array existente. Si llamáramos const sortedTodos = state.todos.sort(), acabaríamos mutando el estado real del store sin querer.
En la Parte 8: Redux Moderno, veremos cómo Redux Toolkit ayuda a evitar mutaciones en reductores, y detecta y alerta sobre mutaciones accidentales fuera de los reductores.
Configuración del Store
Ya hemos visto que podemos pasar los argumentos rootReducer y preloadedState a createStore. Sin embargo, createStore también puede aceptar un argumento adicional, que se usa para personalizar las capacidades del store y dotarle de nuevas funcionalidades.
Los stores de Redux se personalizan mediante algo llamado potenciador de store. Un potenciador de store es como una versión especial de createStore que añade una capa adicional que envuelve al store original de Redux. Un store potenciado puede cambiar cómo se comporta el store, proporcionando sus propias versiones de las funciones dispatch, getState y subscribe del store en lugar de las originales.
Para este tutorial, no entraremos en detalles sobre cómo funcionan realmente los potenciadores de store; nos centraremos en cómo usarlos.
Creación de un Store con Potenciadores
Nuestro proyecto tiene dos pequeños ejemplos de potenciadores de store disponibles en el archivo src/exampleAddons/enhancers.js:
-
sayHiOnDispatch: un potenciador que siempre muestra'Hi'!en la consola cada vez que se despacha una acción -
includeMeaningOfLife: un potenciador que siempre añade el campomeaningOfLife: 42al valor devuelto porgetState()
Empecemos usando sayHiOnDispatch. Primero, lo importaremos y lo pasaremos a createStore:
import { createStore } from 'redux'
import rootReducer from './reducer'
import { sayHiOnDispatch } from './exampleAddons/enhancers'
const store = createStore(rootReducer, undefined, sayHiOnDispatch)
export default store
Aquí no tenemos un valor de preloadedState, así que pasaremos undefined como segundo argumento.
A continuación, intentemos despachar una acción:
import store from './store'
console.log('Dispatching action')
store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about actions' })
console.log('Dispatch complete')
Ahora mira la consola. Deberías ver 'Hi!' registrado allí, entre las otras dos declaraciones de registro:
El potenciador sayHiOnDispatch envolvió la función original store.dispatch con su propia versión especializada de dispatch. Cuando llamamos a store.dispatch(), en realidad estábamos llamando a la función envoltorio de sayHiOnDispatch, que llamó a la original y luego imprimió '¡Hola!'.
Ahora, intentemos añadir un segundo potenciador. Podemos importar includeMeaningOfLife del mismo archivo... pero tenemos un problema. ¡createStore solo acepta un potenciador como tercer argumento! ¿Cómo podemos pasar dos potenciadores al mismo tiempo?
Lo que realmente necesitamos es alguna forma de fusionar los potenciadores sayHiOnDispatch e includeMeaningOfLife en un único potenciador combinado, y luego pasar ese.
Afortunadamente, el núcleo de Redux incluye una función compose que se puede usar para combinar múltiples potenciadores. Usémosla aquí:
import { createStore, compose } from 'redux'
import rootReducer from './reducer'
import {
sayHiOnDispatch,
includeMeaningOfLife
} from './exampleAddons/enhancers'
const composedEnhancer = compose(sayHiOnDispatch, includeMeaningOfLife)
const store = createStore(rootReducer, undefined, composedEnhancer)
export default store
Ahora podemos ver qué pasa si usamos el store:
import store from './store'
store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about actions' })
// log: 'Hi!'
console.log('State after dispatch: ', store.getState())
// log: {todos: [...], filters: {status, colors}, meaningOfLife: 42}
Y el registro resultante se ve así:

Así, podemos ver que ambos potenciadores están modificando el comportamiento del store simultáneamente. sayHiOnDispatch ha cambiado cómo funciona dispatch, e includeMeaningOfLife ha cambiado cómo funciona getState.
Los potenciadores de store (store enhancers) son una forma muy potente de modificar el store, y casi todas las aplicaciones Redux incluirán al menos un potenciador al configurar el store.
Si no tienes ningún preloadedState que pasar, puedes pasar el enhancer como segundo argumento:
const store = createStore(rootReducer, storeEnhancer)
Middleware
Los potenciadores son poderosos porque pueden sobrescribir o reemplazar cualquiera de los métodos del store: dispatch, getState y subscribe.
Pero, muchas veces solo necesitamos personalizar cómo se comporta dispatch. Sería ideal tener una forma de añadir comportamiento personalizado cuando se ejecuta dispatch.
Redux utiliza un tipo especial de complemento llamado middleware para personalizar la función dispatch.
Si has usado bibliotecas como Express o Koa, quizá ya conozcas la idea de añadir middleware para personalizar comportamientos. En estos frameworks, el middleware es código que se sitúa entre la recepción de una solicitud y la generación de una respuesta. Por ejemplo, el middleware de Express/Koa puede añadir cabeceras CORS, registro de eventos (logging), compresión, etc. La mejor característica es que son componibles en cadena: puedes usar múltiples middlewares de terceros en un proyecto.
El middleware de Redux resuelve problemas diferentes pero conceptualmente similares. Proporciona un punto de extensión entre el despacho de una acción y su llegada al reducer. Se usa para registro de eventos (logging), reportes de errores, comunicación con APIs asíncronas, enrutamiento y más.
Primero veremos cómo añadir middleware al store, luego cómo escribir el tuyo propio.
Uso de Middleware
Ya vimos que puedes personalizar el store con potenciadores. El middleware de Redux se implementa sobre un potenciador especial incluido en Redux: applyMiddleware.
Como ya sabemos añadir potenciadores, podemos hacerlo ahora. Comenzaremos con applyMiddleware y añadiremos tres middlewares de ejemplo incluidos en este proyecto.
import { createStore, applyMiddleware } from 'redux'
import rootReducer from './reducer'
import { print1, print2, print3 } from './exampleAddons/middleware'
const middlewareEnhancer = applyMiddleware(print1, print2, print3)
// Pass enhancer as the second arg, since there's no preloadedState
const store = createStore(rootReducer, middlewareEnhancer)
export default store
Como indican sus nombres, cada middleware imprimirá un número al despachar una acción.
¿Qué ocurre si despachamos ahora?
import store from './store'
store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about actions' })
// log: '1'
// log: '2'
// log: '3'
Y vemos la salida en consola:
¿Cómo funciona esto?
El middleware forma una canalización alrededor del método dispatch. Al llamar store.dispatch(action), en realidad invocamos al primer middleware de la cadena. Este puede hacer cualquier operación con la acción. Normalmente verifica si la acción es de un tipo específico que le interesa, similar a un reducer. Si coincide, ejecuta lógica personalizada; si no, pasa la acción al siguiente middleware.
A diferencia de un reducer, el middleware puede contener efectos secundarios, incluyendo timeouts y lógica asíncrona.
En este caso, la acción pasa por:
-
El middleware
print1(que vemos comostore.dispatch) -
El middleware
print2 -
El middleware
print3 -
El
store.dispatchoriginal -
El reducer raíz dentro de
store
Como todas son llamadas a funciones, retornan en orden inverso. Así, print1 es el primero en ejecutarse y el último en finalizar.
Escritura de middleware personalizado
También podemos escribir nuestros propios middleware. Quizás no necesites hacer esto siempre, pero los middleware personalizados son excelentes para añadir comportamientos específicos a una aplicación Redux.
Los middleware de Redux se escriben como una serie de tres funciones anidadas. Veamos cómo es este patrón. Comenzaremos escribiendo este middleware usando la palabra clave function, para que sea más claro lo que sucede:
// Middleware written as ES5 functions
// Outer function:
function exampleMiddleware(storeAPI) {
return function wrapDispatch(next) {
return function handleAction(action) {
// Do anything here: pass the action onwards with next(action),
// or restart the pipeline with storeAPI.dispatch(action)
// Can also use storeAPI.getState() here
return next(action)
}
}
}
Analicemos qué hacen estas tres funciones y cuáles son sus argumentos.
-
exampleMiddleware: La función externa es el "middleware" en sí. Será llamada porapplyMiddlewarey recibe un objetostoreAPIque contiene las funciones{dispatch, getState}del store. Son las mismas funcionesdispatchygetStateque forman parte del store. Si llamas a esta funcióndispatch, enviará la acción al inicio de la cadena de middleware. Esto solo se llama una vez. -
wrapDispatch: La función intermedia recibe como argumento una función llamadanext. Esta función es en realidad el siguiente middleware en la cadena. Si este middleware es el último, entoncesnextes en realidad la función originalstore.dispatch. Llamar anext(action)pasa la acción al siguiente middleware en la cadena. Esto también se llama solo una vez. -
handleAction: Finalmente, la función interna recibe laactionactual como argumento y se llamará cada vez que se despache una acción.
Puedes dar a estas funciones de middleware cualquier nombre que quieras, pero puede ayudar usar estos nombres para recordar lo que hace cada una:
- Externa:
someCustomMiddleware(o como quieras llamar a tu middleware) - Intermedia:
wrapDispatch - Interna:
handleAction
Como son funciones normales, también podemos escribirlas usando funciones flecha de ES2015. Esto nos permite escribirlas más brevemente porque las funciones flecha no necesitan una declaración return, pero también puede ser un poco más difícil de leer si aún no estás familiarizado con ellas y los retornos implícitos.
Aquí está el mismo ejemplo de arriba, usando funciones flecha:
const anotherExampleMiddleware = storeAPI => next => action => {
// Do something in here, when each action is dispatched
return next(action)
}
Seguimos anidando esas tres funciones y devolviendo cada función, pero los retornos implícitos hacen esto más breve.
Tu primer middleware personalizado
Imaginemos que queremos añadir registro de logs a nuestra aplicación. Nos gustaría ver el contenido de cada acción en la consola cuando se despacha, y nos gustaría ver cómo queda el estado después de que la acción haya sido procesada por los reducers.
Estos ejemplos de middleware no son parte específica de la aplicación de tareas real, pero puedes intentar añadirlos a tu proyecto para ver qué sucede cuando los usas.
Podemos escribir un pequeño middleware que registre esa información en la consola:
const loggerMiddleware = storeAPI => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', storeAPI.getState())
return result
}
Cada vez que se despacha una acción:
-
Se ejecuta la primera parte de la función
handleActione imprimimos'dispatching' -
Pasamos la acción a la sección
next, que puede ser otro middleware o elstore.dispatchreal -
Eventualmente los reducers se ejecutan y el estado se actualiza, y la función
nextretorna -
Ahora podemos llamar a
storeAPI.getState()y ver el nuevo estado -
Finalizamos devolviendo cualquier valor
resultque haya venido del middlewarenext
Cualquier middleware puede devolver cualquier valor, y el valor devuelto por el primer middleware en la cadena es lo que realmente se devuelve cuando llamas a store.dispatch(). Por ejemplo:
const alwaysReturnHelloMiddleware = storeAPI => next => action => {
const originalResult = next(action)
// Ignore the original result, return something else
return 'Hello!'
}
const middlewareEnhancer = applyMiddleware(alwaysReturnHelloMiddleware)
const store = createStore(rootReducer, middlewareEnhancer)
const dispatchResult = store.dispatch({ type: 'some/action' })
console.log(dispatchResult)
// log: 'Hello!'
Probemos con otro ejemplo. Los middleware a menudo buscan una acción específica y luego hacen algo cuando esa acción se despacha. También pueden ejecutar lógica asíncrona. Podemos escribir un middleware que imprima algo con retraso cuando detecte cierta acción:
const delayedMessageMiddleware = storeAPI => next => action => {
if (action.type === 'todos/todoAdded') {
setTimeout(() => {
console.log('Added a new todo: ', action.payload)
}, 1000)
}
return next(action)
}
Este middleware buscará acciones de "todo added". Cada vez que vea una, establecerá un temporizador de 1 segundo y luego imprimirá el payload de la acción en la consola.
Casos de Uso de Middleware
Entonces, ¿qué podemos hacer con el middleware? ¡Muchas cosas!
Un middleware puede hacer lo que quiera cuando detecta una acción despachada:
-
Registrar algo en la consola
-
Configurar timeouts
-
Realizar llamadas asíncronas a APIs
-
Modificar la acción
-
Pausar la acción o incluso detenerla por completo
y cualquier otra cosa que se te ocurra.
En particular, el middleware está diseñado para contener lógica con efectos secundarios. Además, el middleware puede modificar dispatch para aceptar elementos que no son objetos de acción simples. Hablaremos más sobre ambos aspectos en la Parte 6: Lógica Asíncrona.
Redux DevTools
Finalmente, hay un aspecto crucial más que cubrir sobre la configuración del store.
Redux fue diseñado específicamente para facilitar la comprensión de cuándo, dónde, por qué y cómo ha cambiado tu estado a lo largo del tiempo. Como parte de esto, Redux permite usar Redux DevTools, una extensión que muestra un historial de las acciones despachadas, su contenido y cómo cambió el estado después de cada acción.
La interfaz de Redux DevTools está disponible como extensión para Chrome y Firefox. Si aún no la tienes instalada, hazlo ahora.
Una vez instalada, abre las herramientas de desarrollo del navegador. Deberías ver una nueva pestaña "Redux". Aún no hace nada; primero debemos configurarla para comunicarse con un store de Redux.
Integración de DevTools en el Store
Con la extensión instalada, debemos configurar el store para que DevTools pueda monitorear su actividad. Esto requiere añadir un enhancer específico.
La documentación de Redux DevTools Extension explica cómo configurar el store, pero los pasos son complejos. Afortunadamente, el paquete NPM redux-devtools-extension simplifica este proceso. Este paquete exporta la función composeWithDevTools que usaremos en lugar de la función compose original de Redux.
Así se implementa:
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import rootReducer from './reducer'
import { print1, print2, print3 } from './exampleAddons/middleware'
const composedEnhancer = composeWithDevTools(
// EXAMPLE: Add whatever middleware you actually want to use here
applyMiddleware(print1, print2, print3)
// other store enhancers if any
)
const store = createStore(rootReducer, composedEnhancer)
export default store
Asegúrate de que index.js siga despachando una acción después de importar el store. Ahora, abre la pestaña Redux DevTools. Deberías ver algo así:

A la izquierda hay una lista de acciones despachadas. Al hacer clic en una, el panel derecho muestra varias pestañas:
-
El contenido del objeto de acción
-
El estado completo de Redux tras ejecutarse el reducer
-
Las diferencias entre el estado anterior y el actual
-
Si está habilitado, el stack trace de la función que originó la llamada a
store.dispatch()
Así se ven las pestañas "State" y "Diff" tras despachar la acción "add todo":


Estas son herramientas poderosas que nos ayudan a depurar aplicaciones y entender exactamente lo que ocurre internamente.
Lo que has aprendido
Como has visto, la store es la pieza central de toda aplicación Redux. Las stores contienen el estado y manejan las acciones ejecutando reducers, además de poder personalizarse para añadir comportamientos adicionales.
Veamos cómo se ve ahora nuestra aplicación de ejemplo:
Y como recordatorio, esto es lo que hemos cubierto en esta sección:
- Las aplicaciones Redux siempre tienen una única store
- Las stores se crean con la API de Redux
createStore - Cada store tiene una única función reducer raíz
- Las stores se crean con la API de Redux
- Las stores tienen tres métodos principales
getStatedevuelve el estado actualdispatchenvía una acción al reducer para actualizar el estadosubscriberecibe una función de callback que se ejecuta cada vez que se despacha una acción
- Los store enhancers permiten personalizar la store al crearla
- Los enhancers envuelven la store y pueden sobrescribir sus métodos
createStoreacepta un enhancer como argumento- Se pueden combinar múltiples enhancers usando la API
compose
- El middleware es la forma principal de personalizar la store
- El middleware se añade usando el enhancer
applyMiddleware - El middleware se escribe como tres funciones anidadas
- El middleware se ejecuta cada vez que se despacha una acción
- El middleware puede tener efectos secundarios
- El middleware se añade usando el enhancer
- Las Redux DevTools permiten ver los cambios en tu aplicación a lo largo del tiempo
- La extensión DevTools puede instalarse en tu navegador
- La store necesita el enhancer de DevTools, usando
composeWithDevTools - Las DevTools muestran las acciones despachadas y los cambios en el estado a lo largo del tiempo
¿Qué sigue?
Ahora tenemos una store Redux funcional que puede ejecutar nuestros reducers y actualizar el estado cuando despachamos acciones.
Sin embargo, cada aplicación necesita una interfaz de usuario para mostrar los datos y permitir al usuario hacer algo útil. En Parte 5: UI y React, veremos cómo la store Redux funciona con una UI, y específicamente cómo Redux puede trabajar junto con React.