React Hooks y Redux funcionando juntos
Integrando Redux con los React Hooks para simplificar nuestro código
La llegada de los hooks a React ha supuesto un cambio en el paradigma del desarrollo de aplicaciones basadas en esta librería: la forma en la que diseñamos nuestras aplicaciones ha cambiado por completo debido a ellos.
La librería React Redux ha sido probablemente una de las grandes afectadas por esta nueva característica. A poco que hayas buscado en Internet habrás encontrado multitud de artículos hablando de cómo sustituir React Redux por los hooks de cara a controlar el estado dentro de los componentes. Sin embargo, su integración con los hooks ha pasado prácticamente desapercibida a pesar de que desde hace un tiempo cuenta con una API para integrarse con ellos:
Es por ello que he preparado este artículo para profundizar más en esta API y ver cómo nos puede ayudar a integrar los hooks dentro de aplicaciones cuya arquitectura está basada en Redux.
¡Vamos a verlo!
Introducción
Como sabréis, la aparición de los React Hooks nos ha dado una alternativa para crear componentes con estado interno, algo que antes estaba restringido a los “Class Components” y que ahora es posible gestionar desde componentes funcionales gracias a los hooks useState
y useReducer
. De este modo, el código generado para tener componentes con estado propio es mucho menor, pues los componentes funcionales requieren menos código “boilerplate” que su contrapartida basada en clases.
Otra de las ventajas que han aportado es una mayor reusabilidad del código cuando empleamos hooks algo que anteriormente debíamos lograr empleando patrones como render props o los high-order components.
Estas ventajas que aporta su uso son, creo, el motivo principal por el que fueron implementados por el equipo de React. Así que, a pesar de la cantidad de artículos que hay sobre como emplear los hooks para sustituir a Redux, no creo que hayan supuesto el final de las librerías destinadas a controlar el estado global de la aplicación.
React Redux 7.1.0
En junio de 2019 fue liberada la versión 7.1.0 de React Redux la cual provee de su propio conjunto de hooks:
- El hook
useSelector()
el cual permite extraer datos de una store de Redux. - Y el hook
useDispatch()
que devuelve una referencia a la funcióndispatch
procedente de una store de Redux con el fin de permitirnos lanzar acciones.
Gracias a ellos, podremos sustituir nuestros Class Components por componentes funcionales donde lo deseemos de modo que podamos reutilizar lógica o reorganizarla de acuerdo a las necesidades de nuestra aplicación.
Por supuesto estos hooks también permiten prescindir del high order component connect
con el cual debíamos envolver a nuestros componentes cuando queríamos conectarlos a la store de Redux.
Todo esto nos permite simplificar el código de nuestra aplicación como podéis ver unas líneas más abajo.
Una aplicación básica con Redux
De cara a ver la diferencia crearemos una aplicación sencilla con Redux que implemente un contador con dos botones que permitan incrementarlo y decrementarlo.

Para ello lo que haremos será partir de un proyecto base de React con Redux y declararemos las siguientes acciones de Redux que permitirán aumentar o decrementar el contador almacenado en la store:

Nuestra store tendrá el siguiente aspecto:

Dado que es una aplicación muy sencilla he decido crear el reducer en el mismo archivo donde se crea la Store pues para este ejemplo no necesitaremos recurrir a técnicas avanzadas como la combinación de reducers mediante la función combineReducer
.
Finalmente, la función encargada de pintar la interfaz será la siguiente:

Donde como veis, estoy recurriendo al high order component connect
de cara a acceder a la store y obtener las acciones para modificarla mapeadas sobre la función dispatch
.
Finalmente, en el archivo index.js
envolvemos nuestro componente App
con el Provider
de Redux para poder acceder en nuestros componentes a la store:

Es decir, un proyecto básico donde emplear Redux para gestionar el estado. Veamos ahora la forma en que podemos refactorizar el componente App.js
de cara a emplear los hooks proporcionados por la librería React-Redux.
Refactorización de App.js
Lo primero que haremos dado que queremos emplear hooks será refactorizar nuestro componente App.js
con el objetivo de transformarlo en un componente funcional:

A pesar de que hemos conseguido reducir algo el código, todavía tenemos que envolver el componente App
con el high order component connect
de cara a obtener las propiedades ( mapStateToProps
) y las acciones ( mapDispatchToProps
) relacionadas con la store de Redux.
Es aquí donde entran los hooks que proporciona la librería React-Redux.
useSelector hook
El hook useSelector
nos permite remplazar la función mapStateToProps
de modo que podamos acceder directamente en la store de Redux sin necesidad de recurrir al high order component connect
para pasar el estado global como propiedades del componente.
Esta función tiene como argumento un callback
que a su vez recibe como argumento la store de Redux completa de modo que lo que devolvamos desde este callback será accesible desde nuestro componente.
En nuestro ejemplo, la store de Redux posee la propiedad count
con el valor inicial de 0. Para acceder a ella mediante el hook useSelector
escribiremos lo siguiente:
const count = useSelector(store => store.count)
Como veis, dentro del callback recibimos la store completa y de ella seleccionamos la propiedad count
para poder usarla dentro de nuestro componente App.js
.

Por tanto y como podeis ver en el código actualizado del componente App.js
ya podemos prescindir de la función mapStateToProps
para acceder a la store de Redux.
Por supuesto, si una acción de Redux provoca un cambio en la propiedad count
de la store, esta propiedad será actualizada provocando un render de nuestro componente.
useDispatch hook
El otro hook que proporciona la librería React Redux es useDispatch
el cual devuelve una función que podremos emplear para enviar acciones a la store de Redux.
Para usarla bastará con pasar una llamada a un “action creator” a la función devuelta por useDispatch
y obtendremos el mismo comportamiento que cuando empleamos la función mapDispatchToProps
.
Gracias a este hook ya podemos prescindir del high order component connect
y reemplazarlo por el hook useDispatch
:

Como podéis observar hemos obtenido un componente App.js
mucho más limpio y que no necesita de connect
para acceder a la store de Redux.
Otra de las ventajas es que toda la lógica del componente se encuentra encapsulada dentro del cuerpo del componente App
por lo que ya no es necesario ir a otro lugar para ver la funcionalidad relacionada con el acceso a Redux. Esto para mí es una de las gran ventajas que supone emplear los hooks proporcionados por React Redux.
Entonces, ¿los hooks reemplezarán a Redux?
Volviendo al debate inicial sobre si los hooks reemplazarán a Redux creo que es importante entender para lo que fueron concebidos cada uno de ellos.
Por un lado, Redux proporciona:
- Un estado determinista, transaccional y aislado de los side-effects.
- Una única fuente de verdad para nuestra aplicación.
- Una forma fácil de compartir el estado global entre diferentes componentes.
- Y una forma de debuggear el estado a lo largo del tiempo.
Por otra parte, los hooks nos permiten:
- Emplear estado interno y acceder al ciclo de vida dentro de los componentes funcionales.
- Reunir la lógica asociada al ciclo de vida en un mismo sitio.
- Compartir el mismo comportamiento entre distintos componentes.
Es decir, los beneficios que aportan y los ámbitos de actuación son bastante distintos y no se superponen. Es más, Redux está más relacionado con la forma en que planteamos la arquitectura de la aplicación, pues básicamente es un subconjunto de la arquitectura Flux la cual entre otras cosas define la forma en que los cambios de estado se producen.
Por tanto pese a que en un principio la presencia de hooks como useReducer
nos podrían causar la impresión de que tenemos una alternativa a Redux (y la multitud de artículos hablando de cómo poder sustituir Redux por los hooks), mi opinión es que ambos son perfectamente compatibles (tal y como hemos visto en el ejemplo anterior) y que no debemos ver los hooks como un sustituto de Redux sino como un complemento.
Repositorio
Si queréis ver el código completo del ejemplo que he usado para ilustrar este articulo podéis descargarlo del siguiente repositorio:
¿Quieres recibir más artículos como este?
Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado: 👇👇👇