Descargo de responsabilidad : este artículo no es una introducción a redux . Hay una serie de buenos recursos para comenzar con redux (ver más abajo ) y le sugiero que comience con ellos. Este artículo tampoco se trata de reaccionar. El término "ciclo de vida" se utiliza en el contexto de las operaciones y el flujo de datos redux.
En solo tres años, redux se ha convertido en una opción bastante popular entre los desarrolladores frontend como la biblioteca de gestión estatal preferida. Más aún en el ecosistema de reacción.
Es asombroso (e impresionante, de verdad) lo pequeño y simple que es el código base. Y, sin embargo, puede manejar situaciones muy complejas con facilidad. Quizás esta simplicidad de redux es un factor importante que impulsa su gran popularidad.
En la siguiente parte , exploraremos cómo el middleware afecta el ciclo de vida de redux y el flujo de datos.
Internamente, redux solo funciona con flujo de datos síncrono y no viene con muchas "partes móviles" o métodos mágicos como otras soluciones.
La configuración de redux más básica se puede considerar como un ciclo único de actualizaciones de estado que se compone de solo 2 componentes:
Las acciones son objetos accesorios que se requieren para descubrir cómo actualizar el estado para la siguiente iteración.
La función reducer toma el estado anterior y la acción enviada como sus argumentos y devuelve el siguiente estado. Si no se necesitan cambios, devuelve el estado anterior tal cual. De lo contrario, crea un nuevo estado y lo devuelve.
Es una práctica común dividir nuestro árbol de estado en múltiples segmentos y escribir un reductor separado para cada segmento de estado. Las acciones pueden o no estar relacionadas con múltiples segmentos de estado. Este proceso de romper nuestros reductores en piezas más pequeñas y fáciles de entender en un proceso llamado Descomposición .
Ciclos de vida de reductores independientes
Ahora podemos combinar varios reductores independientes en un solo reductor (a menudo llamado reductor "raíz") y crear una tienda redux usándolo.
importar {combinedReducers} desde 'redux'
importar fooReducer desde './foo'importar barReducer desde './bar'const rootReducer = combineReducers({foo: fooReducer,bar: barReducer,})
Alternativamente, podríamos excluir el sufijo 'Reductor' de nuestras importaciones para que el código sea más claro .
importar foo desde './foo'importar barra desde './bar'const rootReducer = combineReducers({foo,bar,})
Ciclo de vida básico de Redux
Cuando se envía una acción, el reductor raíz la recibe y pasa el mismo objeto de acción a todos los reductores para que reaccionen de forma independiente. Sin embargo, en lugar de pasar todo el árbol de estado a cada reductor, redux solo pasará el segmento de estado exclusivo del reductor. El valor de retorno de cada reductor se vuelve a fusionar en el árbol de estado completo.
Esta es la arquitectura redux básica y también es la más común. Con una planificación cuidadosa y una división inteligente del estado de la aplicación, la mayoría de las aplicaciones a pequeña escala pueden funcionar con esta arquitectura sin ninguna complejidad adicional.
A medida que su árbol de estado se vuelve complejo, puede encontrarse en situaciones en las que necesita compartir el estado entre diferentes reductores. Una solución rápida es combinar esos reductores en uno solo. Sin embargo, hacerlo generalmente crea reductores de grasa que no escalan bien.
Si queremos mantener nuestros reductores separados, debemos averiguar si necesitamos compartir el segmento de estado actual o la versión actualizada.
Dado que los reductores son solo funciones, podemos pasarles cualquier cantidad de argumentos que queramos. Si un reductor requiere un segmento de estado de otro reductor, podemos pasarlo como el tercer argumento.
Reductores dependientes del estado actual
No podemos combinar reductores dependientes usando la utilidad combineReducers()
que viene con redux.
Una vez que pasa el caso de uso principal para
combineReducers
, es hora de usar más lógica reductora "personalizada": documentos de Redux
Dado que los reductores son solo funciones, podemos pasar el estado de un reductor diferente como tercer argumento.
import foo from './foo'importar bar from './bar'function rootReducer (estado, acción) {const fooState = foo(estado, acción) const barState = bar(estado, acción, estado.foo )
devolver {foo: fooState,bar: barState,}}
Combinación de reductores dependientes del estado actual
Generalmente, cuando un reductor depende del estado de otro reductor, requiere el estado actualizado. Personalmente, nunca me he encontrado con una situación en la que se requiera el antiguo estado. Si conoces alguna experiencia de este tipo, compártela en los comentarios.
Reductores dependientes de estado actualizado
El código se ve casi igual que en la sección anterior. Hemos hecho sólo un pequeño cambio. En lugar de pasar el estado anterior en state.foo
, ahora estamos pasando el estado actualizado en fooState
.
import foo from './foo'importar bar from './bar'function rootReducer (estado, acción) {const fooState = foo(estado, acción) const barState = bar(estado, acción, foo_State_ )
devolver {foo: fooState,bar: barState,}}
Combinación de reductores dependientes de estado actualizado
La dependencia del estado actualizado de otros reductores significa que existe una jerarquía vertical de invocación de reductores. Esto no significa mucho para casos triviales, pero la idea sugiere la posibilidad de encadenar reductores. Sin embargo, el encadenamiento de reductores aumentará exponencialmente la complejidad del código.
Nota : Otra alternativa al problema de las "actualizaciones de segmentos compartidos" sería simplemente poner más datos en la acción. Puedes leer más sobre esto aquí .
Ahora que hemos visto algunos patrones de diseño de reductores y combinándolos de forma aislada, veamos cómo se ven juntos. Aquí hay una lista de cosas clave para observar:
Ciclo de vida completo de Redux
En todos los dibujos, omití intencionalmente a los creadores de acciones y la tienda para mantenerlos limpios y libres de hinchazón. Como sabes: