Esta vez haremos un buscador de imágenes con ayuda de la API de Unsplash y React Query, con el cual notaras un gran cambio en tus aplicaciones, con tan pocas lineas de código, React Query mejorara el rendimiento de tu aplicación!
🚨 Nota: Este post requiere que sepas las bases de React con TypeScript (hooks básicos).
Cualquier tipo de Feedback es bienvenido, gracias y espero disfrutes el articulo.🤗
De una vez vamos a establecer la interfaz de la respuesta de la API, dentro de la carpeta de src/interfaces creamos un archivo index.ts y agregamos la siguientes interfaces.
Recibirá el evento, en el cual tendremos todo lo necesario para recuperar todos los datos de cada input dentro del formulario que en este caso es solo un input.
Ahora vamos a usar la función fromEntries de la instancia de Object mandando una nueva instancia de FormData el caul a su vez recibe la propiedad target del evento.
Esto nos devolverá cada uno de los valores dentro de nuestro formulario. Y el cual podemos desestructurar.
Aunque no nos ayuda el autocompletado para desestructurar cada valor del input
Bueno, ya obtuvimos el valor del input, ahora vamos a validar que si su longitud es 0, que no haga nada.
Y si esa condición no se cumple, entonces ya tendremos nuestra palabra clave para buscar imágenes.
Por cierto, también borrar el formulario y ponerle el foco en el input.
Todo bien, pero ahora el problema es que lo tenemos todo en el componente Form.tsx y necesitamos compartir el estado query para comunicar que imagen vamos a buscar.
Asi que lo mejor es que movamos este código, primero a un custom hook.
Dentro de la carpeta src/hook creamos un archivo index.tsx y agregamos la siguiente función:
exportconstuseFormQuery=()=>{}
Movemos la función handleSubmit dentro del hook y también el estado.
Y retornamos el valor del estado (query) y la función handleSubmit
Por el momento solo vamos a realizar el cascaron de este componente.
Este componente, va a recibir la query (imagen a buscar) por props.
Aquí es donde se hará la petición a la API y mostrar las tarjetas.
import{Card}from'./Card';interfaceIGridResults{query:string}exportconstGridResults=({query}:IGridResults)=>{return (<><pclassName='no-results'>
Results with: <b>{query}</b></p><divclassName='grid'>{/* TODO: map to data and show cards */}</div></>)}
Ahora vamos a usar nuestro GridResults.tsx en src/App.tsx
Lo mostraremos de forma condicional, donde si el valor del estado query (la imagen a buscar) tiene una longitud mayor a 0, entonces se muestra el componente y muestra los resultados que coincidan con la búsqueda.
React Query facilita la obtención, el almacenamiento en caché y la gestión de los datos. Y es lo que recomienda el equipo de React en vez de hacer una simple petición fetch dentro de un useEffect.
Ahora vamos a la terminal a instalar estas dependencias:
npm install @tanstack/react-query axios
Luego de instalar las dependencias, necesitamos envolver nuestra app con el proveedor de React query.
Para ello, vamos al punto mas alto de nuestra app, que es el archivo src/main.tsx
Primero creamos el cliente de React Query.
Envolvemos el componente App con el QueryClientProvider y le mandamos en la prop client nuestro queryClient
Usaremos un hook de react-query que es el useQuery, el cual recibe 3 parámetros, pero por el momento solo usaremos los primeros dos.
El primer parámetro es la queryKey que es un arreglo de valores (arreglos con valores tan simples como un string o complejos como un objeto), nos sirve para identificar los datos que se almacenaban en el cache. En este caso mandamos un arreglo de con el valor de la query.
useQuery([query])
El segundo parámetro el la queryFn, es la función que hace la petición y retorna una promesa ya resuelta con los datos o un error.
Para esto vamos a crear nuestra función, en la carpeta src/utils creamos el archivo index.ts y creamos una función.
Esta función es asíncrona y recibe una query de tipo string y retorna una promesa de tipo ResponseAPI,
Construimos la URL, cabe mencionar que necesitamos una API Key para usar esta API. Solo vas a crear una cuenta en Unsplash. creas una app y obtienes la llave de acceso.
Luego hacemos un try/catch por si algo sale mal.
Dentro del try hacemos la petición con ayuda de axios. Hacemos un get y mandamos la url, desestructuramos la propiedad data y la retornamos.
En el catch solo lanzaremos un error mandando el mensaje.
Ahora si, vamos a usar nuestra función getImages, se la mandamos al hook.
Pero, como esta función recibe un parámetro, necesitamos mandarla de la siguiente manera: creamos una nueva función que retorna el getImages y mandamos la query que nos llega por props
❌ No lo hagas asi.
useQuery([query],getImages(query))
✅ Hazlo asi.
useQuery([query],()=>getImages(query))
Y para tener tipado vamos a poner que la data es de tipo ResponseAPI.
import{Card}from'./Card';interfaceIGridResults{query:string}exportconstGridResults=({query}:IGridResults)=>{const{data,isLoading,error,isError}=useQuery<ResponseAPI>(['images',query],()=>getImages(query))return (<><pclassName='no-results'>
Results with: <b>{query}</b></p><divclassName='grid'>{/* TODO: map to data and show cards */}</div></>)}
Ahora que ya tenemos la data, vamos a mostrar unas cuantos componentes aquí.
1 - Primero una condición, para saber si isLoading esta en verdadero, mostramos el componente Loading.tsx.
2 - Segundo, al finalizar el loading, evaluamos si hay un error, y si existe mostramos el error.
3 - Luego hacemos una condición dentro del elemento p donde si no hay resultados de la búsqueda, mostramos un texto u otro.
4 - Finalmente, recorremos la data para mostrar las imágenes.
Y Listo, ya podríamos dejarlo asi y se vería muy bien
Mostrando el loading:
Mostrando los resultados de la búsqueda:
Pero me gustaría bloquear el formulario mientras el loading esta activo.
Para esto el componente Form.tsx debe recibir otra prop que es isLoading y colocarlo en los valores de las propiedades de disable tanto del input y del botón
En src/App.tsx desestructuramos isLoading y handleSubmit del hook. Y isLoading se lo mandamos al componente Form y la función se la mandamos al GridResults
En el componente GridResults.tsx vamos a recibir la nueva prop que es handleLoading, lo desestructuramos, y dentro del componente realizamos un useEffect antes de las condiciones, y dentro del useEffect ejecutamos handleLoading y le mandamos el valor de isLoading que nos da el hook useQuery y el useEffect se ejecutara cada vez qie el valor isLoading cambie, por eso lo colocamos como dependencia del useEffect.
Y Listo, asi bloquearemos el formulario cuando se este ejecutando la petición.
💧 Conclusión.
Espero que te haya gustado esta publicación y que te haya ayudada a entender un nuevo enfoque para realizar peticiones con react-query! y crecer tu interés en esta librería que es muy usada y muy util, con el cual notas cambios increíbles en el rendimiento de tu app. 🤗
Si conoces alguna otra forma distinta o mejor de realizar esta aplicación con gusto puedes comentarla
Te invito a que revises mi portafolio en caso de que estés interesado en contactarme para algún proyecto! Franklin Martinez Lucas
🔵 No olvides seguirme también en twitter: @Frankomtz361