Agregar Lógica Personalizada Utilizando el Patrón State Reducer y React Custom Hooks

Share this video with your friends

Send Tweet
Published a year ago
Updated 10 months ago

Nuestro componente wizard implementa el patrón state reducer y expone varios hooks personalizados para permitir al usuario definir como utilizar el componente, es decir, nuestro Wizard sólo define la lógica básica de su funcionamiento. Por medio del patrón state reducer, nuestro Wizard expone acceso al estado interno permitiendo crear lógica personalizada que permite utilizar el componente para realizar otras acciones. En este caso se agrega una nueva acción al reducer y un nuevo estado que permiten obtener los datos de un comic de XKCD para mostrarlo en una de las páginas del Wizard, y también modifica los controles de navegación permitiendo avanzar a la siguiente página utilizando el botón de búsqueda.

Matías Hernández: [0:00] Nuestro componente Wizard ya está completo y puede ser utilizado de diferentes formas. ¿Qué podemos hacer con este y el patrón useReducer? Podemos agregar lógicas por medio de un reducer personalizado.

[0:11] Digamos que queremos mostrar un comic de XKCD en base a una búsqueda. Primero comenzaremos haciendo un pequeño refactor de nuestro Wizard. Removemos este destructuring aquí y obtenemos el estado, pero pasaremos el estado completo a nuestro contexto utilizando destructuring de nuevo y también la función dispatch() para poder ser utilizada externamente.

[0:31] Volvemos a nuestra aplicación. Lo que queremos es mostrar un formulario dentro de una Página 1. Vemos que todo funciona correctamente. Para eso iremos a nuestro componente Page1 y lo refactorizaremos para poder mostrar nuevos componentes. Agregaremos los elementos HTML necesarios, que son un label, un input y un botón.

[0:50] También necesitamos un estado que manejar. Para eso utilizaremos React.useState que nos retorna una dupla con el valor del estado comicId y la función setComicId. Utilizaremos este estado para pasarlo al input como valor y utilizaremos el evento onChange para definir el valor de este estado utilizando setComicId. Nuestro input funciona.

[1:12] Ahora necesitamos implementar la función de búsqueda. Utilizaremos el evento onClick dentro del botón y pasaremos la función search.

[1:20] Debemos definir search que será una función asíncrona que efectuará un request, o una llamada a la API correspondiente. Lo primero que está función realizará es revisar si comicId existe y si es un valor numérico. De ser así, podremos efectuar nuestra llamada, pero esta es una función asíncrona.

[1:38] Corregimos esta pequeña falta, agregamos async y ahora podemos efectuar nuestra llamada. Primero definiremos la URL que utilizaremos. La dejaremos en blanco igual. Crearemos una variable llamada response. Utilizaremos await para esperar esta función asíncrona fetch().

[1:53] Una vez que tengamos la respuesta volvemos a utilizar await y utilizamos el método json() para obtener los datos de este response. ¿Qué hacemos con estos datos? Tenemos que buscar dónde guardarlos y cómo efectuar el siguiente paso que es navegar a la Página 2.

[2:10] Aquí es donde entra en juego el patrón useReducer. Recordemos que nuestro Wizard acepta initialState y reducer. Crearemos un nuevo inicio de state personalizado que tendrá un objeto llamado comicData, que es un objeto vacío por defecto, y un nuevo reducer, que recibe un estado y una acción.

[2:26] Este reducer actuará sobre una acción personalizada que hemos llamado COMIC_FETCHED. Si la acción es de ese tipo, entonces retornará el estado original, utilizando destructuring, y comicData estará completado con el valor del payload que viene dentro de action. En caso contrario simplemente retornará el estado.

[2:50] Pasamos estas props a nuestro Wizard, initialState como initialState y reducer como reducer. Ahora ya podemos volver a nuestro componente Page1.

[3:00] Haremos uso de otra de las API de nuestro Wizard, en este caso useWizardContext donde obtenemos dispatch para poder emitir el evento y goNextPage para poder navegar a la siguiente página. Con dispatch podemos emitir la acción comicFetched que definimos en nuestro propio reducer.

[3:17] Por eso agregamos dispatch({ type: 'COMIC_FETCHED }) y como payload agregamos los datos obtenidos desde la llamada a la API de XKCD y ahora llamamos a goNextPage. Nos falta definir la URL de XKCD. Para eso obtenemos simplemente la URL desde este ejemplo y utilizamos template literals para poder concatenar con nuestro comicId real.

[3:39] En este ejemplo la API de XKCD tiene un problema con cors así que utilizaremos un Proxy llamado cors-anywhere. Copiamos esta URL y lo utilizamos acá. Definimos la variable proxy y concatenamos ambas URL dentro de la llamada app fetch. No olvidemos que estamos haciendo uso de async/await. Es aconsejable que utilicemos el bloque try...catch para verificar que todo esté en orden.

[4:02] Tomamos este trozo de código y lo ponemos dentro del bloque try. Ahora ya podemos probar nuestro nuevo input. Agregamos una idea cualquiera, 124. Ponemos buscar y vemos que al hacer click en buscar navega a la Página 2 y tenemos el resultado de nuestro JSON.

[4:16] Ahora actualizaremos la Página 2 para poder desplegar esta información. Simplemente hacemos uso nuevamente de useWizardContext para obtener el estado, en este caso, el atributo comicData, y de este comicData utilizamos destructuring para obtener el título, el número, la imagen y el texto alternativo.

[4:36] Agregamos algunos elementos HTML para mostrar estos datos, un h2 para mostrar el título y el número y un elemento img para mostrar la imagen y el texto alternativo. Volvemos atrás y podemos probar agregar un id cualquiera. Número 45, pulsamos buscar y nos carga Schrodinger, que es el comic 45 y podemos ver la imagen.

[4:56] Tenemos un formulario completamente funcional utilizando el patrón state reducer para agregar acciones personalizadas y estado personalizado compartido a través del context del propio Wizard.