Usando Redux en React
Hoy en día, uno de los mayores desafíos en el desarrollo es el manejo de la arquitectura de estado dentro de una aplicación. Para esto, se creó una biblioteca, hoy aclamada consistentemente por su capacidad, organización y manejo de estado: Redux. Sobre ella aprenderemos más aquí.
¿Qué es un estado?
Antes de ensuciarnos las manos, es esencial entender el concepto de estado y para qué sirve. Imagina que tienes una aplicación que, cuando realizas un tipo especial de interacción (como añadir un objeto al carrito o filtrar lo que quieres ver), es necesario que cierta cantidad de información sea temporalmente conservada mientras la pantalla no se cierra o actualiza. Ese rinconcito donde se almacena esta información se conoce como estado. Sin él, todo 10 veces más estresante de implementar en React. En pocas palabras, un completo desastre.
Redux
Figura 1 - Emblema de Redux
Ahora que entendemos la importancia y funcionalidad de un estado, asumiremos la situación donde tenemos un componente llamado Input y, dentro de él, otro elemento llamado Exibidor. El componente Input también tiene un elemento de ingreso de tipo de texto que, cuando escribimos algo, éste debe aparecer en un elemento h1 creado en el Exibidor. Usaremos estados para lograr esto:
Figura 2 - Demo de componente Input
Figura 3 - Demostración del componente Exibidor
Como podemos ver en las imágenes previas, no hay mucha dificultad en pasar un estado de un componente “padre” a uno “hijo”. Todo lo requerido se enviará al “hijo” como propiedad, igual que lo hecho para el componente Exibidor. Sin embargo, la situación se complica cuando debemos pasar un estado a un componente muy distante en una jerarquía particular (el "hijo" del “hijo” para el que tenemos el estado, por ejemplo). O cuando los componentes que necesitan la información de un estado específico no tienen conexión directa con el componente que la almacena.
En estos casos, se requerirá un esfuerzo repetitivo (pasar la propiedad con el estado a todos los componentes) o ni siquiera será posible hacer esto (caso de los componentes sin relación jerárquica). Para resolver esto fue justo por lo que se creó Redux.
Redux es una biblioteca enfocada en manejar el estado de aplicaciones JavaScript, de modo que un archivo particular dentro del proyecto sea responsable de almacenar todos los estados que necesiten compartirse o cambiarse por un cierto número de componentes. Explicado lo anterior, podemos empezar con su instalación y configuración inicial, a fin de que esté listo para usarse.
Instalar y configurar Redux
El primer paso es crear la aplicación de React, así que llamemos intuitivamente nuestro primer proyecto con Redux. ¿Qué tal proyecto-react-redux?
npx create-react-app project-react-redux
cd project-react-redux
npm start
Nota: Usamos npm como un paquete de herramientas de manejo, pero siéntete libre de elegir lo que más se ajuste a tus preferencias o necesidades.
Como este artículo explica cómo funciona Redux, comenzaremos con una implementación simple. ¿Qué opinas de tomar el mismo ejemplo de arriba, pero sin esa relación “padre-hijo”?
Figura 4 - Componente de la app con los componentes de Input y Exibidor
Figura 5 - Componente actualizado de Input
Figura 6 - Componente actualizado de Exibidor
Nótese que fue necesario hacer varios cambios a los componentes. Primero, el componente Input ahora tiene un botón que usaremos en el futuro para enviar el estado local del componente al global de Redux. Se recomienda enviar información completa en lugar de varias actualizaciones (como en el caso de onChange). Eso generaría mucho rendering innecesario para la aplicación. Asimismo, el componente Exibidor no muestra aún ninguna información dentro del elemento h1. Eso porque todavía falta configurarlo para acceder al Redux y traer la data que se mostrará. En este punto, debemos crear la estructura básica que recibirá la implementación Redux.
Una vez creado el ambiente de desarrollo, debemos instalar la biblioteca Redux. Ejecuta en la carpeta raíz del proyecto la siguiente línea de comando, a través de la terminal:
npm install redux react-redux
Después de la instalación, crearemos las tres estructuras Redux principales: store, reducer y actions. Para fines de organización, se sugiere crear un directorio y un archivo índice por cada elemento, como se muestra a continuación:
Figura 7: Estructura del directorio Redux
Para recapitular
Hasta ahora hemos creado un proyecto con dos componentes: enviar (Input) y recibir (Exibidor) información al Redux. Además de eso, instalamos Redux y creamos un directorio y un archivo índice para cada estructura esencial: store, actions y reducer. Ahora entenderemos para qué son y cómo configurarlas.
Actions
Actions son funciones que dicen a Redux qué debe actualizarse y cómo debe ocurrir eso. Cada acción resalta una meta que necesita cumplir nuestra aplicación.
Siempre habrá funciones que retornen un objeto con, al menos, dos elementos o keys:
- Type: Contiene un string que describe la acción que debe realizarse;
- Payload: Contiene la data proveniente de nuestra aplicación.
Al traer estos conceptos al ejemplo que usamos, pasamos ahora a crear una acción llamada actionSave con un tipo igual a REGISTRA_NOME y un payload igual al estado local del componente Input, el cual vendrá como parámetro en la función.
Figura 8: Ajustando una acción
Configuración del Reducer
El Reducer es responsable de recibir las solicitudes de las acciones y actualizar el estado existente del store. Es el intermediario entre lo que debe hacerse y lo que está almacenado.
Es una función que recibe el estado y la acción como parámetros. Estas dos piezas de información actualizarán el estado según cada elemento o key pasado. Para hacerlo, usamos un Switch que recibe el tipo de key y tiene un caso para cada acción creada. En nuestro caso, solo tenemos una:
Figura 9: Ajustando el reducer
Nota: Tengamos en consideración que se creó una constante llamada INITIAL_STATE. Esta será el estado inicial de nuestra aplicación y si el estado (denotado como parámetro de estado) está vacío, usaremos en su lugar el estado inicial que creamos. Adicionalmente, podrás ver que, como mencionamos, hay un caso construido para el tipo actionSave. En este caso, la acción es guardar en el estado el texto enviado. En otras palabras, le decimos al reducer que en cualquier momento que reciba como parámetro una actividad con un tipo igual a REGISTRA_NOME, debe guardar en el estado la información mantenida en el key payload.
Store
El Store es el punto de la aplicación donde se almacenarán todos los estados que usaremos. A través de éste, guardaremos y recuperaremos la información de estado y la pasaremos a cualquier componente que queramos (con los ajustes adecuados, por supuesto).
Para crear un store, usaremos la función nativa de Redux llamada createStore. Dicha función puede recibir más de un parámetro para ayudar en la implementación. Sin embargo, para propósitos de aprendizaje (y no confundirte), usaremos solo un parámetro obligatorio: el reducer creado en el paso anterior.
Figura 10: Configurando el Store
Para recapitular
En los últimos pasos, configuramos la estructura principal del Redux: creamos una acción que define qué y cómo debe actualizarse en el estado global de la aplicación, un reducer que ejecuta la acción y, finalmente, un store donde el reducer almacenará este estado.
¿Cómo se comunica la aplicación con Redux?
Si prestaste atención hasta aquí, habrás notado que nuestros componentes Input y Exibidor aún no tienen conexión con nuestro action, reducer y store. En el último paso, necesitamos completar la implementación del Redux y, para ello, usaremos el componente Provider, así como los hooks useDispatch y useSelector.
Provider
El Provider es el componente que dirá a nuestra aplicación que tenemos un estado global creado con Redux y que está disponible para acceder a él. Para esto, dicho componente debe ser importado de react-redux y encapsular toda la parte que tendrá acceso al Redux. Considerando que nuestra implementación es el componente App, lo encapsularemos con el Provider.
IMPORTANTE: El Provider es un componente que debe tener una propiedad llamada store, donde enviaremos el store que construimos para Redux como valor. Obsérvalo aquí:
Figura 11: Implementando el Provider
UseSelector y UseDispatch
Usamos los dos hooks ya mencionados para acceder al estado global generado con Redux. Mientras el useSelector se emplee para leer el estado global, el useDispatch se usará para actualizarlo.
Importamos el useSelector de react-redux y lo asignamos a una constante que, en este ejemplo, llamaremos globalState. El useSelector recibe una función como parámetro que obtiene el estado global del Redux. De esta forma, simplemente retornando a este mismo estado, tendremos acceso a lo que necesitamos:
Figura 12: useSelector en el componente Viewer
El useDispatch es una función que ordena una acción al reducer. Así, debemos crear también una constante que recibirá el useDispatch. Esto, en cambio, será empleado para enviar actualizaciones al estado global y, en nuestro caso, enviaremos como parámetro el actionSave que creamos:
Figura 13: useDispatch en el componente Input
Figura 14: Ejecutando la aplicación
Y voilà! ¡Nuestra aplicación con Redux está lista!
Consideraciones finales
Como puedes anticipar, programar requiere práctica y mucha repetición. Con Redux no es diferente. Puede parecer un poco complejo de implementar a la primera. No obstante, su existencia abre puertas y facilita las implementaciones, sin mencionar que el mercado lo emplea frecuentemente. Creer en Redux brinda recompensas.
Revelo Content Network da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.