Cuando desarrollamos aplicaciones con la biblioteca de React, detectamos la importancia de fluir eficientemente los datos internos generados desde los componentes y los externos que llegan a nuestra aplicación, usualmente desde una API.
Dependiendo de la situación, aplicamos un Hook específico para esta gestión.
Haremos una combinación de esta gestión:
- useState para un manejo interno de datos en un componente
- useReducer combinado con useContext para involucrar un estado global sin tener que trasladar datos con props.
Crearás un sistema de operación CRUD involucrando un flujo de datos eficiente a través de useState, useContext y useReducer, incluyendo la comunicación a través de un API.
Este artículo está dirigido a personas que han aprendido React en un nivel básico y quieren empezar a utilizar de una manera más extensa las funcionalidades en el manejo de datos.
¿Qué encontrarás en este artículo?
- Preparación de nuestro ambiente básico en React con react-router-dom.
- Generamos un servidor sencillo con json-server.
- Establecer una sección para realizar creación y edición de usuarios. Asimismo, una más para observar una lista de los mismos.
Lo que vas a aprender
Al terminar este artículo, serás capaz de:
- Aplicar tres hooks de React, permitiéndote fluir datos por toda la aplicación.
- Extraer los datos externos desde una API externa, con React.
Desarrollo de la aplicación
Para la construcción de la aplicación, la dividiremos en 4 pasos:
- Preparación de ambiente.
- Desarrollo de Context.
- Lectura de usuarios y flujo hacia componentes.
- Creación de usuarios y actualización de la lista en el componente.
Preparación de ambiente
Crea una aplicación con React.
Posteriormente, necesitaremos instalar dos dependencias:
axios
será utilizado para el consumo de datos y json-server
para la creación de un servidor local con fake data
, que podremos usar a través de un puerto específico.
Ahora bien, cuando generamos estos documentos y archivos. Tendremos que hacer algunas modificaciones.
La estructura de tus documentos debe quedar de esta forma:
Dentro de estos archivos, consideramos:
- Una carpeta
components
, donde se incluyen 2 archivos. En estos, trabajaremos el desarrollo de la aplicación y consumo de datos. - Una carpeta
config
el cual incluye unaxios.js
. Aquí, al momento de comunicarnos a través del API, estableceremos la configuración específica para nuestras llamadas. - Una carpeta
context
, en el cual, a través de la misma, estructuramos nuestro "Context". Asimismo, desarrollaremos unUserReducer
que contará con la gestión del estado global (UserState
), para ser transferido a los componentes a través del contexto.
Finalmente, unos archivos nuevos encontrados fuera de la carpeta src
.
db.json
. Un archivo con el cual, a través de la dependencia dejson-server
, simularemos la transacción de una base de datos simple.
Insertamos ahí mismo:
db.json
.env.
Nuestras variables de entorno. Establecemos dentro:
Listo. Levantamos nuestra aplicación a través de dos terminales separadas. El primero alzará React
, el segundo nuestro servidor local.
¡Comencemos a desarrollar!
Desarrollo de Context
Primero, establecemos nuestra App.js
con esta configuración:
Después, accedemos a ListUsers.js
. Dejamos muy sencilla la aplicación por ahora para no obtener errores.
Con esto listo, vamos a proceder a desarrollar nuestro contexto y estado global.
React Context es un método que permite transferir props de un componente padre a sus hijos, a través del almacenamiento de datos en un store, sin realizarlo de manera manual, por nivel. En una explicación más general, cualquier componente hijo puede acceder a estos valores mientras esté situado debajo del componente padre.
Accedemos a UserContext.js
y preparamos nuestro Context
.
Ahora, accedemos a UserState.js
y dentro, preparamos nuestro estado inicial, transferido a través de un Provider
en nuestro Context
.
Bien. Ahora accedemos a App.js
y anclamos UserState
como el componente padre hacia el resto de la aplicación.
El resultado será nuestra página con el valor del contexto ya disponible para los componentes.
En caso de que no lo tengas instalado, utilizo React Developer Tools para el navegador de Firefox. Aunque, también está disponible para Google Chrome.
Ahora, hagamos un último ajuste dentro de ListUsers.js
para bajar los datos desde el contexto.
Entre estos últimos cambios, destacamos:
- El uso de
useContext
para consumir el estado directamente en el componente. - Realizamos una desestructuración de objetos con el valor de
users
, el cual es un arreglo vacío.
Una vez establecido esto, ahora trabajemos nuestro estado global y usemos el concepto de reducer
para gestionarlo.
Lectura de usuarios y flujo hacia componentes
En esta sección, nos conectaremos a nuestro servidor local a través axios
, obtendremos los usuarios y los guardamos en nuestro estado global (globalState
). Finalmente, fluiremos los datos al componente para su consumo y muestra.
Comencemos configurando el archivo que creamos llamado axios.js
, el cual establecerá a través de la variable de entorno que creamos anteriormente, la URL base para las llamadas API.
Listo. Accedamos a nuestro UserState.js
y agregamos:
Considera varios puntos aquí:
- Hacemos la importación de nuestro
UserReducer.js
(aún no trabajamos) y el archivo deaxios.js
a partir del nombre declientAxios
. - Utilizamos el hook de
useReducer
para permitir la creación de un estado global, gestionado por una función llamadareducer
, la cual a través de las acciones y el disparadordispatch
permitirán su manipulación. - Creamos una función llamada
readUsers
. Dentro, haremos una llamada conaxios
con el método GET y obtendremos los usuarios. Destacamos que es una función asíncrona, por lo tantoasync-await
son imprescindibles. - Una vez obtenida la respuesta, en caso de que todo haya sucedido correctamente aplicamos
dispatch
donde le pasaremos como argumento unaction
, el cual es un objeto que contiene dos propiedades:type.
El nombre del tipo de acción que ejecutaremos en elreducer
.payload.
Información que enviaremos al reducer, con el cual, manipularemos el estado global.
- Finalmente, en el retorno, añadimos
readUsers
al atributo devalue
para que pueda ser consumida por todos los componentes.
Bien. Ahora, hagamos el cambio en el reducer:
UserReducer.js
El reducer
es una función el cual recibe dos parámetros:
globalState.
El cual es el estado actual en el cual se encuentra nuestro estado.action.
Es el objeto que viene de nuestrodispatch
, el cual comprende los dos valores que comentamos anteriormente,type
ypayload
.
Observa con cuidado que realizamos un switch
y este mismo, evalúa el action.type
para identificar cómo vamos a manipular el estado global. Identificamos READ_USERS
y entonces realizamos un retorno para hacer las modificaciones.
Con esto terminado, estamos listos para trabajar el componente. Vamos a ListUsers.js
El cambio principal realizado es a través de useEffect
, el cual, de manera asíncrona y una vez que el componente ha sido cargado por primera vez, realiza la invocación de getResponse
.
getResponse
es obtenido a través del contexto y permite la obtención de los datos a través de la comunicación con nuestro servidor local.
Si todo sucedió correctamente, obtendremos esta resultado:
Creación de usuarios y actualización de la lista en el componente
Como último paso, vamos a realizar la creación de usuarios a través del API.
Primero, anexamos el componente FormUser.js
a nuestro App.js
:
Hacemos un cambio en nuestro UserState.js
:
Bien. Vayamos por partes.
- Generamos una nueva función llamada
addUser
.- Ejecutamos como parámetro un valor
data
que contendrá los datos reales que vengan del formulario del componente. - Realizamos una desestructuración de objetos de los valores que vienen del formulario.
- Llamamos con un método POST y usando los datos disponibles del formulario, a nuestro servidor local para crear un nuevo usuario.
- Realizado esto, ejecutamos un
dispatch
el cual realice un ajuste dentro de nuestroreducer
.
- Ejecutamos como parámetro un valor
- Esta función
addUser
la incorporamos dentro de nuestro retorno, en los atributos devalue
.
Entramos a UserReducer.js
y hacemos el ajuste:
Para cerrar, entremos al componente de FormUser.js
Este será nuestro resultado terminado:
Para aclarar este último componente, lo que hicimos fue:
- Importamos
useState
para el manejo de estado local del componente. Realizamos una desestructuración de arreglos para obteneruser
que funcionará como el estado local ysetUser
para su manipulación de valor. - Contamos con dos funciones adicionales.
handleChange
que nos permite capturar los datos de los formularios y agregarlos al estado.setData
que nos permitirá enviar los datos para ser ejecutados por eldispatch
enUserState.js
. - Contar con un formulario que contiene un atributo
onSubmit
para ejecutar el formulario. Y, cadainput
con atributosname
, dando el nombre del campo de texto.
Conclusiones
Uno de los procesos con más constancia en una aplicación web es el consumo y manejo de datos. Con este artículo, fue posible explorar la estructura de carpetas que debemos realizar, así como el manejo de Context
con la combinación de un estado global, gestionado por useReducer
.
Recuerda que la práctica hace al maestro. Ve paso a paso. Con calma.
Te invito a conocer el repositorio terminado.