Video Summary and Transcription
Esta charla cubre patrones avanzados para la gestión de API en aplicaciones React a gran escala. Introduce el concepto de una capa de API para gestionar las solicitudes de API de una manera más organizada y mantenible. Los beneficios de usar una capa de API incluyen una mejor mantenibilidad, escalabilidad, flexibilidad y reutilización de código. La charla también explora cómo manejar estados y estatus de API en React, y proporciona ejemplos de cancelación de solicitudes con Axios y React Query. Además, explica cómo usar la capa de API con React Query para una gestión de API simplificada.
1. Introducción a la Gestión de API en React
Bienvenidos a Patrones Avanzados para la Gestión de API en Aplicaciones React a Gran Escala. Hoy, cubriremos la gestión de solicitudes de API en React, el manejo de diferentes estados de API, la creación de hooks personalizados, la cancelación de solicitudes con Axios y React Query. Realizar solicitudes de API en React puede llevar a la duplicación de código y la falta de reutilización. Para abordar esto, podemos implementar una capa de API. Al crear un archivo base de API e importarlo en otros archivos de API, podemos gestionar las solicitudes de API de una manera más organizada y mantenible.
Hola, y bienvenidos a Advanced Patterns para la Gestión de API en Aplicaciones React a Gran Escala. Mi nombre es Tomasz Fienli y soy un desarrollador web y móvil full-stack con nueve años de experiencia en programación. Soy co-propietario de Fienli web tech y mentor y consultor en CodeMentor.io. También soy el autor de los libros Vue y React the Road to Enterprise, así como escritor técnico para Telerik y los blogs Road to Enterprise. Ahora, vamos a ver lo que vamos a cubrir hoy. Así que, en primer lugar, comenzaremos con cómo gestionar las solicitudes de API en React de una manera escalable y flexible con una capa de API. Luego veremos cómo manejar diferentes estados de API mientras realizamos solicitudes de API. También crearemos hooks personalizados para gestionar las solicitudes y estados de API, así como cómo cancelar solicitudes con Axios y una capa de API. Finalmente, echaremos un vistazo a cómo usar React Query y la capa de API y cómo cancelar solicitudes con ellos.
Bueno, entonces, ¿cómo podemos realizar solicitudes de API en React? En realidad, es bastante simple, ¿verdad? Podemos, por ejemplo, usar Axios para eso. Podemos simplemente importarlo y usarlo en nuestros componentes. Y, bueno, puede funcionar bien para, digamos, pequeñas aplicaciones. Pero hay algunos problemas a medida que el proyecto crece, especialmente los grandes, realmente. Entonces, ¿cuáles son los principales problemas con este enfoque? En primer lugar, la code duplicación y la falta de reutilización. Porque imagina que necesitamos, por ejemplo, obtener información sobre un usuario, digamos en la página de inicio de sesión, la página de registro, y la página de perfil del usuario. Así que, todos estos tendrían, bueno, el mismo fragmento de code. Así que, Axios obtiene un punto final de URL y así sucesivamente, ¿verdad? Así que eso no es realmente reutilizable. Y también, bueno, es difícil de mantener. Porque si tuviéramos que hacer cualquier cambio en este code, como digamos, por ejemplo, el cambio de punto final de URL o tuviéramos que cambiar el formato de la carga útil, o, digamos, tuviéramos que migrar de usar Axios a algo como Firebase, ¿verdad? Necesitaríamos visitar cada componente que es Axios y cambiarlos. Bueno, eso no es realmente genial, para ser honesto. Así que, vamos a ver cómo podemos solucionar estos problemas implementando una capa de API. Así que, primero, comenzaríamos con un archivo base de API, donde importaríamos Axios y crearíamos una nueva instancia con alguna configuración predeterminada, como, por ejemplo, una URL base. Luego tenemos una función de API que básicamente devuelve métodos de envoltura de API alrededor de nuestro cliente Http en este caso, Axios. Y finalmente, lo exportamos. Lo siguiente que podemos hacer es, podemos usar este archivo base de API e importarlo en otro archivo de API. Así que, por ejemplo, en este caso, tendríamos un archivo de API de usuarios. Porque queremos hacer algunas cosas con los usuarios, como obtener información sobre los usuarios, agregar un nuevo usuario, y así sucesivamente. En este ejemplo, tenemos tres métodos, listar usuarios, obtener usuario y agregar usuario. Y como puedes ver, todos ellos utilizan los métodos de API del archivo base de API. ¿Y cómo usaríamos esto en un componente ahora? Así que, básicamente, lo que haríamos es, importaríamos un método de API del directorio de API,
2. Beneficios y Flexibilidad de la Capa API
La capa API en React te permite abstraer los detalles de los puntos finales de la API y cambiar fácilmente entre diferentes clientes HTTP. Al separar la lógica de la API en una capa separada, tus componentes permanecen agnósticos a la implementación subyacente. Esto mejora la mantenibilidad, escalabilidad y flexibilidad. Puedes agregar fácilmente nuevos métodos de API, reemplazar el cliente HTTP y mejorar la capa de API con lógica personalizada. La reutilización del código también se incrementa, ya que los métodos de API se pueden importar y utilizar en cualquier parte de la aplicación. El patrón de la capa de API es agnóstico al marco, lo que lo hace adecuado para varios entornos de desarrollo.
y luego simplemente usarlo en un componente. Entonces, como puedes ver, el componente no tiene que pensar en qué tipo de punto final de API tiene que ser golpeado, ¿verdad? El método de API se encarga de eso. Entonces, ¿qué pasa si queremos usar un cliente HTTP diferente, digamos, por ejemplo, Firebase en lugar de Axios. Entonces, nuestro archivo base de API se vería un poco diferente. Aquí, simplemente importaríamos algunos métodos necesarios de Firebase, inicializaríamos la aplicación Firebase. Y luego exportaríamos lo que necesitamos, por ejemplo, Firebase, Firestore, que nos da métodos para básicamente, bueno, conectar con la database, y así sucesivamente, y otras cosas como funciones de almacenamiento de autenticación, etc. Ahora, en el archivo de API de usuario, tendríamos de nuevo los mismos métodos, como listar usuarios, obtener usuario y agregar usuario. Sin embargo, en este caso, estamos usando Firebase, por supuesto, debajo del capó. Pero veamos cómo se vería desde la perspectiva del componente ahora. Bueno, en realidad, para el componente, nada cambiaría, porque todavía importaría el método de API del archivo de API de usuarios, y simplemente lo ejecutaría, ¿verdad? Así que eso es algo realmente genial de la capa de API, porque es como una caja negra para tus componentes. Porque tus componentes realmente no tienen que preocuparse por lo que usas para realizar solicitudes. Sólo le preocupa qué métodos deberías llamar, qué tipo de entrada debería proporcionar y qué tipo de salida puede esperar. Mientras puedas preservar este contrato de entrada y salida, no necesitas hacer ningún cambio en tus componentes. Sólo necesitas hacer cambios en la capa de API, en realidad.
Ahora, echemos un vistazo a los beneficios de la capa de API. En primer lugar, la mantenibilidad, ya que todo el code relacionado con la API está en un solo lugar. Scalability, ya que puedes agregar fácilmente nuevos métodos y archivos de API. Y también tenemos flexibilidad, es mucho más fácil reemplazar el cliente HTTP, y también mejorar la capa de API con lógica personalizada. Así que como acabas de ver, reemplazamos el acceso con Firebase y no necesitamos hacer ningún cambio en el componente. También la reutilización del code, porque los métodos de API pueden ser simplemente importados y utilizados en cualquier parte de la aplicación. Y el patrón de la capa de API también es agnóstico al framework.
3. Manejo de Estados de API en React
Exploremos cómo manejar los estados de API en las aplicaciones React. El uso de indicadores booleanos para cada estado puede llevar a la duplicación de código y complejidad. Podemos mejorar esto utilizando estados de API e implementando un useApiStateUseHook. Los cuatro estados de API son Idle, Pending, Success y Error. Al abstraer los estados, podemos gestionar las solicitudes de API de manera más eficiente.
Bien, a continuación, veamos cómo podemos manejar los estados de API. Lo que he visto en muchas aplicaciones es básicamente el uso de indicadores booleanos. Por ejemplo, si quieres mostrar un spinner, tendrías un estado isLoadingState. Si quieres mostrar un error, si por ejemplo la solicitud falló, tendrías un indicador isError. Y veamos si queremos inicializar una solicitud más tarde. Por ejemplo, si un usuario hace clic en un botón, o si un usuario se desplaza hasta un cierto elemento, entonces también podemos tener un indicador isInitialized. Así que como puedes ver aquí, tenemos tres estados diferentes, y todos ellos se actualizan en consecuencia.
Sin embargo, el problema, y aquí como puedes ver, si se inicializó, mostraría un botón. Si está cargando, mostramos un mensaje de carga data, canDisplaySpinner. Si hubo un error, entonces hubo un problema. Y finalmente, si todo salió bien, estamos mostrando los data. Pero sí. Sin embargo, el problema es que para cada estado de API, necesitamos un nuevo hook de estado, ¿verdad? Porque tenemos inicializado, está cargando, es un error. Así que ya son tres estados. Eso es solo para una solicitud de API. Si necesitamos hacer dos solicitudes, podríamos necesitar tener seis estados. Si necesitamos hacer tres solicitudes, podríamos necesitar nueve, y así sucesivamente. Pero eso no es realmente genial.
Así que veamos cómo podemos mejorarlo utilizando estados de API en su lugar. Y también implementaremos un useApiStateUseHook para ayudarnos con eso. En primer lugar, tenemos cuatro estados de API diferentes. Idle, que significa que básicamente la solicitud aún no ha comenzado. Y tenemos pendiente, que significa que la solicitud se está realizando. Y luego también tenemos éxito y error. Así que obviamente, éxito es para cuando la solicitud se completó con éxito, y error si hubo un problema. También tenemos un array aquí, que básicamente solo exporta las constantes, ya que lo necesitaremos en un momento. Así que vayamos ahora a useApiStateUseHook. En primer lugar, necesitamos importar useState y useMemo. Y también obtenemos la constante idle, ya que es nuestro estado inicial para el hook. Y también obtenemos los estados predeterminados.
4. Gestión de Estados de API en React
Podemos usar el useApiStateUseHook para gestionar los estados de API en React. Con este hook, podemos tener un solo estado que contenga todos los estados de API, como inactivo, pendiente, éxito y error. Podemos actualizar fácilmente el estado de la API utilizando el método setApiStatus. Al implementar un hook useAPI personalizado, podemos mejorar aún más la gestión de la API en React. Este hook acepta un método para ejecutar solicitudes de API y un objeto de configuración para establecer datos iniciales en el estado.
Y la razón por la que los necesitamos es porque queremos básicamente tomar todos nuestros estados y luego básicamente devolver un objeto con los estados, como si estuviera inactivo, pendiente, tuvo éxito, tuvo un error, como puedes ver en el lado derecho de la diapositiva. Y solo uno de ellos estará activo en un momento dado. Entonces, por ejemplo, al principio, solo isIdle se establecerá en verdadero.
Y ahora, aquí está nuestro useApiStateUseHook. Así que tenemos nuestro estado para ello. Así que en comparación con los indicadores booleanos, solo tenemos un estado que contiene todos los estados de la API. Y solo uno de ellos puede estar activo al mismo tiempo. Luego, tenemos el resultado de prepareStateUses. Como mencioné, es un objeto que tiene su estado inactivo, pendiente, y así sucesivamente. Y usamos useMemo aquí para que solo se vuelva a evaluar si el estado de la API cambia. Y luego, finalmente, devolvemos un objeto con apiStatus, el método setApiStatus, y todos los estados normalizados.
Ahora, veamos cómo podemos usarlo. Entonces, como puedes ver aquí, básicamente inicializamos el hook useApiStatus, y podemos pasar el estado inactivo allí, aunque es el estado predeterminado de todos modos. Si queremos comenzar con pendiente inmediatamente, puedes hacerlo. Y luego desestructuramos todos los estados, así como el método setApiStatus, que luego se usa para básicamente actualizar este estado de la API en consecuencia. Antes de que se inicie la solicitud, lo establecemos en pendiente. Si se completa con éxito, lo establecemos en éxito. Si hay un problema, lo establecemos en error. Y como puedes ver en el marcado, básicamente podemos agregar operadores ternarios, ¿verdad? Si está inactivo, entonces hacemos algo. Si está pendiente, entonces mostramos el spinner o el mensaje de carga. Si es un error, entonces un error, y así sucesivamente. Así que es mucho más limpio de esta manera. No necesitamos tener tantos indicadores booleanos. Y el code es mucho más limpio y conciso.
Entonces, ahora veamos cómo podemos mejorarlo aún más implementando un hook useAPI personalizado. Entonces, en primer lugar, importamos useState de nuevo, así como el hook useApiStatus que acabamos de cubrir, y tres estados de api. Entonces, pendiente, éxito y error. Luego, useAPI acepta dos parámetros. El primero es el método que ejecutará una solicitud de API, y el segundo es un objeto de configuración. Entonces, por ejemplo, en este ejemplo, podemos pasar data inicial dentro del objeto de configuración y establecerlo en el estado para los data.
5. Gestión de Estados y Solicitudes de API
Dentro del hook useAPI, la función exec se encarga de establecer los estados de la API, actualizándolos en función del estado de la solicitud, y gestionando los estados de datos y errores. El hook useAPI devuelve un objeto con datos, estado de la API, error y método exec.
Además del estado data, también tenemos un estado para el error, y por supuesto inicializamos el hook useApiStatus. Ahora, a continuación, dentro del hook useAPI, tenemos la función exec. Entonces, como puedes ver, lo que hace es, se encarga básicamente de establecer los estados de la API y actualizarlos en consecuencia, dependiendo del estado de la solicitud. También se encarga de establecer los data después de que la solicitud se haya completado con éxito, y también se encargará de establecer el error si hubo un problema, y lo eliminará si se supone que una solicitud debe comenzar de nuevo. Y finalmente, el método exec devuelve un objeto con data y error si necesitamos manejarlos. Y por último, pero no menos importante, simplemente devolvemos todo desde el hook useAPI data, estado de la API error exec y así sucesivamente.
6. Uso del Hook de API y Cancelación de Solicitudes
Para usar este hook, impórtalo y pasa el método que ejecuta la solicitud de API. El hook devuelve un objeto con los estados de la API, datos y un método exec. Dependiendo del estado, se devuelve el marcado apropiado. Para cancelar solicitudes con Axios y la capa de API, mejora la capa de API con lógica de aborto. El método con aborto acepta un método de Axios y devuelve una función. La función crea un método de cancelación y token, mejora el objeto de configuración y ejecuta la solicitud. Si hay un error, el método isCancel comprueba si la solicitud fue cancelada. Envuelve los métodos del envoltorio de API con aborto para completar la configuración. Por ejemplo, en una función de cuadro de búsqueda, se puede hacer una solicitud de API para autocompletar.
Y ahora, ¿cómo podemos usar este hook? Entonces, obviamente, necesitamos importarlo y luego simplemente pasar el método que se supone que ejecuta la solicitud de API. Entonces, en este caso, estamos pasando un método que simplemente devolverá el resultado de getUser, que obviamente proviene de la capa de API. Y desde el uso de API, recibimos un objeto del cual desestructuramos los estados normales, los data y el método exec. Y como puedes ver en el JSX, de nuevo, dependiendo del estado, simplemente devolvemos el marcado apropiado. Entonces, ya sabes, para cada estado inactivo, el botón para iniciar la búsqueda para gastar el spinner y así sucesivamente.
Bueno, ahora, ¿cómo podemos cancelar solicitudes al usar Axios con la capa de API? Entonces, en realidad, podemos mejorar la capa de API con lógica de aborto. Entonces, en el archivo base de API, agregaríamos el método con aborto que primero aceptaría la función. Entonces, esta función sería uno de los métodos de Axios, como Axios.get, Axios.put, post, y así sucesivamente. Luego, con aborto devuelve una función, que, básicamente, estos argumentos deberían ser los que se pasan al método de Axios. Entonces, por ejemplo, URL, cuerpo y configuración. Y lo que estamos haciendo allí es que necesitamos obtener acceso a la configuración original. Y la razón de ello es porque como parte de esta configuración, queremos pasar una propiedad de aborto, que debería tener una función como valor. Y lo que estamos haciendo aquí, si abort es una función de hecho, entonces creamos un nuevo método de cancelación y el token de cancelación usando el método de origen de Axios, y en el objeto de configuración, asignamos este token de cancelación, y, finalmente, ejecutamos el método de aborto y pasamos el cancelador allí. Y verás lo que hicimos en un momento. Y finalmente, después de mejorar el objeto de configuración, simplemente ejecutamos la solicitud. Reenviamos todos los parámetros además del último. La razón de ello es porque no queremos pasar la configuración original con la propiedad de aborto, sino que queremos pasar nuestro propio objeto de configuración mejorado que no tiene la propiedad de aborto pero podría tener un token de cancelación. Y ten en cuenta que es importante que usemos await aquí porque si hubo un error... Básicamente, sin await, este error no sería capturado en el contexto de con aborto. Y por eso necesitamos await aquí. Y luego finalmente, si hay un error, usamos el método isCancel de Axios para comprobar si la solicitud fue cancelada. Y si lo fue, básicamente establecemos una propiedad abortada en el objeto de error y simplemente lanzamos el error más adelante para que pueda ser manejado desde fuera. Entonces vamos... Bueno, una cosa más. También necesitamos envolver, por supuesto, nuestros métodos de envoltura de API con aborto. Entonces, como mencioné antes, primero pasamos los métodos de acceso y luego lo inicializamos de nuevo y reenviamos todos los parámetros.
Bueno, así es como podemos usarlo. Ahora, entonces, imagina básicamente una función como un cuadro de búsqueda. Por ejemplo, el usuario puede introducir alguna consulta y se hará una solicitud de API para buscar alguna información. Por ejemplo, para autocompletar.
7. Almacenando Canceladores y Manejando Errores
Para almacenar el método cancelador entre re-renderizados, utilizamos ref. El operador de encadenamiento opcional asegura que el método cancelador se ejecute si existe. La propiedad abort en el objeto de configuración recibe el método cancelador como argumento y lo asigna al ref. La declaración catch verifica si el error fue abortado. Los detalles de implementación del cliente HTTP están abstraídos, y solo necesitamos proporcionar la propiedad abort.
Entonces tenemos dos estados, uno para los data que se obtendrán de la API y uno para la consulta que introduce el usuario. Y también tenemos el ref de búsqueda. Esa es una parte importante aquí. Porque lo que necesitamos es ser capaces de almacenar el método cancelador entre re-renderizados, ¿verdad? Por eso lo pondremos en el ref. Pero primero, echemos un vistazo a la función onQueryChange.
Entonces, ¿qué está pasando aquí? Bueno, obviamente estamos estableciendo el valor de entrada en la consulta, pero eso realmente no es la parte importante aquí. Pero aquí, antes de que se inicialice la solicitud, estamos intentando cancelar la anterior. Sin embargo, puede que no haya métodos canceladores cuando se inicializa onQueryChange por primera vez. Por eso usamos el operador de encadenamiento opcional. Básicamente, si hay un método cancelador, ejecútalo. Pero si no lo hay, entonces está bien. No nos importa, pero no queremos que el motor de JavaScript lance un error aquí, ¿verdad? Por eso usamos el operador de encadenamiento opcional. Y luego, como parte de aquí, la propiedad abort. Básicamente, como parte del objeto de configuración, pasamos esta propiedad abort que recibe una función. Y el método cancelador se pasa como primer argumento. Y luego podemos asignar este cancelador en el ref. Así que cuando se inicialice de nuevo onQueryChange, tendremos acceso a este cancelador. Y finalmente, en la declaración catch, básicamente comprobamos si el error fue abortado. Y lo fue. Y lo realmente genial de la forma en que está implementado es que básicamente los detalles de implementación del cliente HTTP, que se accede en este caso, no se filtraron en nuestro componente en absoluto. No tuvimos que importarlo en ningún lugar. Más bien, solo tenemos que proporcionar la propiedad abort. Y ahí es donde obtenemos el método cancelador. Lo establecemos en el ref, y voilà, está disponible para nosotros. Y podemos simplemente llamarlo.
8. Uso de la Capa API con React Query
El uso de la capa API con React Query es simple. Importa el método API y el hook de React Query necesario, como useQuery. Pasa la clave de consulta y el método API, luego desestructura los datos requeridos, el método refetch y los estados. Renderiza el contenido basado en el estado.
Bueno, ahora veamos cómo podemos usar la capa API con React Query. Pero en realidad, es bastante simple, porque realmente lo único que necesitamos hacer es importar el método API de la capa API. También importamos el hook que necesitamos de React Query, como por ejemplo, useQuery en este caso. Y luego simplemente lo usamos. ¿Verdad? Pasamos la clave para la consulta, luego pasamos nuestra lista. Bueno, en este caso, lista usuarios. Así que el método API. Y simplemente desestructuramos lo que necesitamos. Así que, por ejemplo, en este caso, obtenemos data. Obtenemos el método refetch, que puede ser utilizado para inicializar la solicitud. Y también obtenemos nuestros estados normales. De nuevo, y esta parte es básicamente la misma que lo era con, digamos, con nuestro propio hook use API, ¿verdad? Y dependiendo del estado, renderizamos el contenido apropiado. ¿Y cómo podemos cancelar una solicitud al usar la capa API con React Query? Bueno, de nuevo, podemos básicamente pasar una propiedad abort. Sin embargo, esta vez, lo que estamos haciendo es que no estamos usando un ref, sino que tenemos una variable cancelar, y asignamos este método cancelar que fue pasado a través de la propiedad abort a esta variable cancelar. Porque lo cierto es que la forma en que React Query funciona es que espera una propiedad cancelar disponible en la promesa que se devuelve. Por eso necesitamos hacerlo de esta manera. Pero también es muy conciso y limpio. Y finalmente, si quieres cancelar la solicitud, sólo necesitamos llamar a cancel queries. Eso es todo por hoy. Aquí están los enlaces al repositorio de Github con ejemplos completos de code, diapositivas para esta charla, y sitios web donde puedes encontrarme. Además, tengo un regalo especial para todos los asistentes a la conferencia. React el Camino a Enterprise llega este diciembre. Es un libro avanzado con mejores prácticas, patrones y técnicas que cubre muchos conceptos variados como la arquitectura de proyectos escalables, la gestión de estados locales y globales, el manejo de API de pruebas, la optimización del rendimiento, SSG y SSI con Next.js, y más. Puedes obtener un 35% de descuento con el código REACTADVANCED. Bueno, espero que hayas disfrutado de esta charla ¡y feliz codificación!
Comments