Hola a todos, soy nuevo en React JS y me quedé atrapado en un problema que no puedo entender cuál es la causa. Así que estoy tratando de crear un componente de campo de búsqueda que solo active una llamada API después de que un usuario termine de escribir. Lo que sucedió es que después de ingresar la búsqueda, setTimeout se ejecuta varias veces. Me temo que esto haría múltiples llamadas api innecesarias. Apreciaría mucho su ayuda. ¡Gracias!
principal.tsx
import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import './index.css' ReactDOM.createRoot(document.getElementById('root')!).render( <App /> )
Aplicación.tsx
import { useState } from 'react' import fetchData from './utils/fetch' import { WeatherModel } from './model/Weather' function SearchField() { let timer = 0 const [city, setCity] = useState('New York') const handleFetchWeather = async () => { const data: WeatherModel = await fetchData(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${WEATHER_API_KEY}&units=metric`) console.log(data) } const handleSetCity = (e) => { if(timer) clearTimeout(timer) setCity(e.target.value) timer = setTimeout(() => { console.log(city) // handleFetchWeather() }, 2000) } return ( <div className="search"> <input type="text" placeholder="Search city..." onChange={handleSetCity} /> </div> ) } export default SearchField
Múltiples registros de la consola después de ingresar la búsqueda
Puedes usar Debounce :
Aquí hay un ejemplo:
useEffect(() => { let debounce; if (debounce) { clearTimeout(debounce); debounce = null; } debounce = setTimeout(() => { // DO SOMETHING AFTER TIMEOUT ENDS setSearchEntry(searchValue); }, 1 * 1000); }, [setSearchEntry, searchValue]);
Buena suerte :)
Estoy de acuerdo con la solución de rebote, pero también si no lo sabía, este código podría ser aún más simple para usted, por lo que cada vez que se vuelve a procesar un componente, el temporizador se establece en 0 nuevamente, por lo que para persistir el valor, imagina que necesitas ponerlo en un estado, así:
import { useState } from "react"; function SearchField() { const [city, setCity] = useState("New York"); const [timer, setTimer] = useState(0); const handleFetchWeather = async () => { const data = await fetch( `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${WEATHER_API_KEY}&units=metric` ); console.log(data); }; const handleSetCity = (e) => { if (timer) { clearTimeout(timer); } setCity(e.target.value); setTimer( setTimeout(() => { console.log(city); // handleFetchWeather() }, 2000) ); }; return ( <div className="search"> <input type="text" placeholder="Search city..." onChange={handleSetCity} /> </div> ); } export default SearchField;
Ahora, cada renderizado, el componente recordará su valor anterior ;)
El evento onChange en el campo de entrada se activará en cada nueva entrada de carácter, obtenga más información aquí .
Creo que la mejor solución, en este caso, es agregar un botón de envío que activa handleSetCity() y su onChange debería establecer una variable de estado para que sea más fácil manejar los datos.