React JS setTimeout 被多次执行
React JS setTimeout gets executed multiple times
大家好,我是 React JS 的新手,我遇到了一个无法找出原因的问题。因此,我正在尝试制作一个搜索字段组件,该组件仅在用户完成输入后触发 API 调用。发生的事情是,在输入 setTimeout 后,搜索被多次执行。恐怕这会造成多次不必要的 api 调用。非常感谢您的帮助。谢谢!
main.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 />
)
App.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
键入搜索后的多个控制台日志
您可以使用 Debounce:
这是一个例子:
useEffect(() => {
let debounce;
if (debounce) {
clearTimeout(debounce);
debounce = null;
}
debounce = setTimeout(() => {
// DO SOMETHING AFTER TIMEOUT ENDS
setSearchEntry(searchValue);
}, 1 * 1000);
}, [setSearchEntry, searchValue]);
祝你好运:)
输入字段中的 onChange 事件将在每次输入新字符时触发,了解更多信息 here。
在这种情况下,我认为最好的解决方案是添加触发 handleSetCity() 的提交按钮,并且您的 onChange 应该设置一个状态变量,以便更容易处理数据。
我同意 debounce 解决方案,但如果你不知道,这段代码对你来说可能更简单,所以每次组件重新渲染时,计时器都会再次设置为 0,所以为了要持久化该值,假设您需要将其置于一种状态,就像这样:
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;
现在,每次重新渲染,组件都会记住它之前的值;)
大家好,我是 React JS 的新手,我遇到了一个无法找出原因的问题。因此,我正在尝试制作一个搜索字段组件,该组件仅在用户完成输入后触发 API 调用。发生的事情是,在输入 setTimeout 后,搜索被多次执行。恐怕这会造成多次不必要的 api 调用。非常感谢您的帮助。谢谢!
main.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 />
)
App.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
键入搜索后的多个控制台日志
您可以使用 Debounce:
这是一个例子:
useEffect(() => {
let debounce;
if (debounce) {
clearTimeout(debounce);
debounce = null;
}
debounce = setTimeout(() => {
// DO SOMETHING AFTER TIMEOUT ENDS
setSearchEntry(searchValue);
}, 1 * 1000);
}, [setSearchEntry, searchValue]);
祝你好运:)
输入字段中的 onChange 事件将在每次输入新字符时触发,了解更多信息 here。
在这种情况下,我认为最好的解决方案是添加触发 handleSetCity() 的提交按钮,并且您的 onChange 应该设置一个状态变量,以便更容易处理数据。
我同意 debounce 解决方案,但如果你不知道,这段代码对你来说可能更简单,所以每次组件重新渲染时,计时器都会再次设置为 0,所以为了要持久化该值,假设您需要将其置于一种状态,就像这样:
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;
现在,每次重新渲染,组件都会记住它之前的值;)