在 onChange 函数中使用时超时不清除

Timeout not clearing when used in onChange function

我正在为我正在使用的网站创建搜索功能。当用户输入关键字时,将发送一个获取请求以检索匹配的信息。但是,每次按下一个键都让它触发,感觉很浪费。假设用户想要搜索三明治,他们很可能会很快连续输入我只想在用户停止输入一定时间后(比如 250 毫秒)触发它。我的想法是设置一个超时,将在连续击键时清除。不幸的是,超时不会重置,只会被延迟。我尝试将它放在 useEffect 挂钩中,然后超时工作正常,但我遇到了一些其他问题,促使我尝试这样做。

    const onChangeBrand = (e) => {
        const brand = e.target.value
        setBrand(brand)
        const timeout = setTimeout(()=>{
            url.get(`brands?search=${encodeURI(brand.toLowerCase())}&rows=5`)
                .then(res => {
                    setBrands(res.data)
                    if(res.data.length === 1 && res.data[0].urlEncoding === encodeURI(brand.toLowerCase())){
                        setPageType("models")
                    }else{
                        setPageType("brands")
                    }
                })
        },2500)
        return () => clearTimeout(timeout);
    }

如有任何帮助,我们将不胜感激!

你的想法是对的,但执行是错误的。从 onChange 处理程序返回一个函数本质上什么都不做——这在 useEffect 中可以正常工作,所以我知道它来自哪里。这种模式被称为 throttling / debouncing a function and there are tons of premade libraries out there to help you throttle a function (like lodash.throttle),但是自己旋转非常酷!

这里的关键是:

  1. 使用方法范围外的超时变量
  2. 在开始执行您的 onChange 时,检查超时变量是否有值——如果有,请清除它。
  3. 执行onChange,分配新的超时时间。

您可以在这里使用 ref 或其他东西,但我个人认为完全在组件范围之外定义超时持有者是最简单的。

let CHANGE_TIMEOUT = null;

function MyComponent(props) {

// .. component code

    const onChangeBrand = (e) => {
        if (CHANGE_TIMEOUT) {
          // we already have a previous timeout, clear it.
          clearTimeout(CHANGE_TIMEOUT);
        }

        const brand = e.target.value
        setBrand(brand)

        // Set the timeout again
        CHANGE_TIMEOUT = setTimeout(()=>{
            url.get(`brands?search=${encodeURI(brand.toLowerCase())}&rows=5`)
                .then(res => {
                    setBrands(res.data)
                    if(res.data.length === 1 && res.data[0].urlEncoding === encodeURI(brand.toLowerCase())){
                        setPageType("models")
                    }else{
                        setPageType("brands")
                    }
                })
        },2500);
      }

// .. other component code here

}