【问题标题】:Debounce function call, and clear trailing ones去抖函数调用,并清除尾随函数
【发布时间】:2020-09-07 15:12:53
【问题描述】:

使用 React 并尝试从我的文本输入值更改中消除函数调用。

我有一个文本输入,每次inputValue 更改useEffect 都会被触发,并且正在使用输入的值从 API 获取数据:

  useEffect(() => {
    console.log('useEffect');
    fetchDataFromAPI();
  }, [inputValue]);

我希望对fetchDataFromAPI 进行去抖并清除所有尾随的去抖调用。

到目前为止我尝试的是:

const debounce = (func, wait, immediate) => {
  let timeout;

  return function executedFunction() {
    var context = this;
    var args = arguments;

    var later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };

    var callNow = immediate && !timeout;
    console.log('clearTimeout');
    clearTimeout(timeout);

    timeout = setTimeout(later, wait);

    if (callNow) func.apply(context, args);
  };
};


const AsyncComponent = ({
  value,
}) => {
  const [inputValue, setInputValue] = useState('');
  const fetchOptions = async () => console.log('fetchOptions');
  const debouncedFetch = debounce(() => fetchOptions(), 1000);

  useEffect(() => {
    console.log('useEffect');
    debouncedFetch();
  }, [inputValue]);

  return (
    <Autocomplete
      value={value}
    />
  );
};

Source

然而,这段代码的作用是它不会取消尾随的函数调用。 API调用去抖动1000ms,但API调用的数量与inputValue的变化相同。

输入四个字母的结果

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    您当前是在每次组件呈现时声明debouncedFetch 函数的 实例,并且每个函数实例对timeout 变量都有不同的绑定。

    要么在组件外声明去抖函数:

    const debounce = (func, wait) => {
      let timeout;
      return () => {
        var later = function() {
          timeout = null;
          func();
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    };
    const fetchDataFromAPI = () => console.log('fetchOptions');
    const debouncedFetch = debounce(() => fetchDataFromAPI(), 1000);
    const MyApp = () => {
      useEffect(debouncedFetch, [inputValue]);
      // etc
    }
    

    或者移出timeout 变量,以便每次渲染对debouncedFetch 的调用都具有对单个timeout 绑定的一致引用:

    let timeout;
    const debounce = (func, wait) => {
      return () => {
        var later = function() {
          timeout = null;
          func();
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    };
    const fetchDataFromAPI = () => console.log('fetchOptions');
    
    const MyApp = () => {
      const debouncedFetch = debounce(() => fetchDataFromAPI(), 1000);
      useEffect(debouncedFetch, [inputValue]);
      // etc
    }
    

    如果您需要传递参数,而不是使用 arguments.apply(context, args),我认为如果您在传递的 回调 中管理它会更容易阅读,例如:

    useEffect(() => debouncedFetch('arg1', 'arg2'), [inputValue]);
    

    【讨论】:

    • 绝妙的答案!
    猜你喜欢
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多