El prop贸sito de este post es ense帽ar una manera sencilla de como realizar un peque帽o buscador con un efecto debounce.
Dicho proyecto puede extenderse de muchas maneras, pero tratare de hacerlo algo b谩sico pero eficiente.
馃毃 Nota: Este post requiere que sepas las bases de React con TypeScript (hooks b谩sicos y peticiones con fetch).
Cualquier tipo de Feedback es bienvenido, gracias y espero disfrutes el articulo.馃
鈻讹笍 CSS vanilla (Los estilos los encuentras en el repositorio al final de este post)
聽
馃巿 驴Qu茅 es el efecto "Debounce"?
El efecto rebote (debounce) es cuando no se ejecutan al momento de su invocaci贸n. En lugar de eso, su ejecuci贸n es retrasada por un periodo predeterminado de tiempo. Si la misma funci贸n es invocada de nuevo, la ejecuci贸n previa es cancelada y el tiempo de espera se reinicia.
聽
馃巿 Creando el proyecto.
Al proyecto le colocaremos el nombre de: search-debounce (opcional, tu le puedes poner el nombre que gustes).
npm init vite@latest
Creamos el proyecto con Vite JS y seleccionamos React con TypeScript.
Luego ejecutamos el siguiente comando para navegar al directorio que se acaba de crear.
cd search-debounce
Luego instalamos las dependencias.
npm install
Despu茅s abrimos el proyecto en un editor de c贸digo (en mi caso VS code).
code .
聽
馃巿 Primeros pasos.
Dentro de la carpeta src/App.tsx borramos todo el contenido del archivo y colocamos un componente funcional que muestre un titulo.
Ahora creamos la carpeta src/components y dentro de la carpeta creamos el archivo Input.tsx y dentro agregamos lo siguiente:
exportconstInput=()=>{return (<><labelhtmlFor="pokemon">Name or ID of a Pokemon</label><inputtype="text"id="pokemon"placeholder="Example: Pikachu"/></>)}
Una vez hecho, lo importamos en el archivo App.tsx
馃毃 Nota: Esta NO es la 煤nica forma para realizar este ejercicio, solo es una opci贸n! Si tienes una mejor manera, me gustar铆a que la compartieras por los comentarios por favor. 馃槍
En este caso voy a manejar el estado del input en un nivel superior, o sea, el componente App del archivo App.tsx
Esto lo haremos, debido a que necesitamos el valor del input disponible en App.tsx, ya que ahi se har谩 la petici贸n a la API y el efecto debounce.
1 - Primero creamos el estado para manejar el valor del input.
const[value,setValue]=useState('');
2 - Creamos una funci贸n para que actualice el estado del input cuando el input haga un cambio.
Esta funci贸n recibe como par谩metro el evento que emite el input, de dicho evento obtendremos la propiedad target y luego la propiedad value, la cual es la que mandaremos a nuestro estado.
Y as铆 ya tenemos controlado el estado de nuestro input. 馃コ
聽
馃巿 Creando la funci贸n para la petici贸n a la API.
Ahora creamos la carpeta src/utils y dentro colocamos un archivo llamado searchPokemon.ts y agregamos la siguiente funci贸n para hacer la petici贸n, y buscar un pokemon por su nombre o ID.
馃毃 Nota: La respuesta de la API tiene m谩s propiedades de las que se representa en la interfaz ResponseAPI
Esta funci贸n recibe dos par谩metros:
pokemon: es el nombre o ID del pokemon.
signal: permite establecer escuchadores de eventos. En otras palabras, nos ayudara a cancelar la petici贸n HTTP cuando el componente se desmonte o haga un cambio en el estado.
Esta funci贸n retorna la data del pokemon si todo sale bien o null si algo sale mal.
Ahora, creamos un efecto para que cuando el valor del input cambie, ejecutamos la funci贸n setTimeout que actualizara el estado del debouncedValue enviando el nuevo valor del input, despu茅s de 1 segundo, y asi obtendremos la palabra clave o sea el pokemon, para hacer la petici贸n a la API.
Al final del efecto, ejecutamos el m茅todo de limpieza, que consiste en limpiar la funci贸n setTimeout, es por eso que la guardamos en una constante llamada timer
Una vez que tenemos el valor del input ya con el efecto debounce, toca hacer la llamada a la API.
Para eso usaremos al funci贸n que creamos con anterioridad, searchPokemon.tsx.
Para ello, vamos a usar un efecto.
Primero creamos el controller el cual es el que nos ayudara a cancelar la petici贸n HTTP, como mencionamos antes
Dentro del controller tenemos dos propiedades que nos interesan:
abort(): al ejecutarse, cancela la petici贸n.
signal: mantiene la conexi贸n entre el controller y el la petici贸n para saber cual se debe cancelar.
El abort() lo ejecutamos al final, al momento de que se desmonte el componente.
La dependencia de este efecto sera el valor del debouncedValue, ya que cada vez que cambie este valor, debemos hacer una nueva petici贸n para buscar al nuevo pokemon.
Y como la funci贸n searchPokemon regresa una promesa y dentro del efecto no es permitido usar async/await, usaremos .then para resolver la promesa y obtener el valor que retorna.
4 - Y ahora por ultimo, agregamos una ultima condici贸n, en donde evaluamos si el pokemon existe (o sea que no es nula) y si es un objeto vaci贸 retornamos un fragmento.
Esto es as铆 ya que el estado inicial para almacenar a los pokemon sera un objeto vac铆o "{}".
Si no colocaremos esa condici贸n, entonces la inicio de nuestra app, incluso sin haber tecleado nada en el input, ya nos aparecer铆a el mensaje de "No results", y la idea es que aparezca despu茅s de que hayamos tecleado algo en el input y se haya hecho la llamada a la API.
Ahora dentro del efecto donde hacemos la llamada a la API mediante la funci贸n searchPokemon, antes de hacer la llamada enviamos el valor de true al setIsLoading para activar el loading.
Despu茅s, una vez obtenida la data dentro del .then le enviamos dicha data al setPokemon (el cual puede ser el pokemon o un valor nulo).
Y finalmente enviamos el valor de false al setIsLoading para quitar el loading.
Tenemos mucha l贸gica en nuestro componente por lo que es necesario separarla en diversos archivos:
L贸gica para controlar el input.
L贸gica del debounce.
L贸gica para hacer la llamada a la API y manejar el pokemon.
Y como esta l贸gica hace uso de hooks como es useState y useEffect, entonces debemos colocarlos en un custom hook.
Lo primero sera crear una nueva carpeta src/hooks
1. Manejando la l贸gica para controlar el input.
Dentro de la carpeta src/hooks creamos el siguiente archivo useInput.ts
Y colocamos la l贸gica correspondiente al manejo del input.
Dentro de la carpeta src/hooks creamos el siguiente archivo useSearchPokemon.ts.
Colocamos la l贸gica relacionada con hacer la petici贸n a la API y mostrar el pokemon.
Este custom hook recibe como par谩metro un string llamado search, que es el nombre del pokemon o el ID. Y ese par谩metro se lo enviamos a la funci贸n que hace la llamada a la API searchPokemon
馃毃 Nota: Observe la parte del If en el efecto, al final colocamos un else donde si el debouncedValue esta vaci贸,nno haremos una llamada a la API y le mandamos el valor de un objeto vaci贸 a setPokemon
Dentro de la carpeta src/hooks creamos el siguiente archivo useDebounce.ts y colocamos toda la l贸gica para manejar el efecto debounce.
Este custom hook, recibe 2 par谩metros:
value: es el valor del estado del input.
delay: es la cantidad de tiempo que quieres retrasar la ejecuci贸n del debounce y es opcional.
馃毃 Nota: la propiedad delay la usamos el segundo par谩metro de la funci贸n setTimeout, donde en caso de que delay sea undefined, entonces el tiempo por defecto sera 500ms.
Y tambi茅n, agregamos la propiedad delay al arreglo de dependencias del efecto.