如何在React.js中执行debounce ?

我想撤消handleOnChange。

我尝试debounce(这。handleOnChange, 200)但它不起作用。

function debounce(fn, delay) {
  var timer = null;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  };
}

var SearchBox = React.createClass({
  render: function() {
    return <input type="search" name="p" onChange={this.handleOnChange} />;
  },

  handleOnChange: function(event) {
    // make ajax call
  }
});

当前回答

2022 -使用useEffect钩子

此时最好的选择是使用useEffect钩子。useEffect允许您设置一个函数,该函数可以修改状态以响应某些异步事件。debounging是异步的,因此useEffect可以很好地用于此目的。

如果从钩子返回一个函数,返回的函数将在钩子再次被调用之前被调用。这让您可以取消之前的超时,有效地解除函数。

例子

这里我们有两个状态,value和tempValue。设置tempValue将触发useEffect钩子,该钩子将启动一个1000ms超时,该超时将调用一个函数将tempValue复制为value。

钩子返回一个取消定时器设置的函数。当钩子再次被调用时(即按下另一个键),超时被取消并重置。

const DebounceDemo = () => {
  const [value, setValue] = useState();
  const [tempValue, setTempValue] = useState();

  // This hook will set a 1000 ms timer to copy tempValue into value
  // If the hook is called again, the timer will be cancelled
  // This creates a debounce
  useEffect(
    () => {
      // Wait 1000ms before copying the value of tempValue into value;
      const timeout = setTimeout(() => {
        setValue(tempValue);
      }, 1000);

      // If the hook is called again, cancel the previous timeout
      // This creates a debounce instead of a delay
      return () => clearTimeout(timeout);
    },
    // Run the hook every time the user makes a keystroke
    [tempValue]
  )

  // Here we create an input to set tempValue. 
  // value will be updated 1000 ms after the hook is last called, 
  // i.e after the last user keystroke.
  return (
    <>
      <input 
        onChange={
          ({ target }) => setTempValue(target.value)
        }
      />
      <p>{ value }</p>
    </>
  )
}

其他回答

这里有一个工作的TypeScript示例,供那些使用TS并想要debounce async函数的人使用。

function debounce<T extends (...args: any[]) => any>(time: number, func: T): (...funcArgs: Parameters<T>) => Promise<ReturnType<T>> {
     let timeout: Timeout;

     return (...args: Parameters<T>): Promise<ReturnType<T>> => new Promise((resolve) => {
         clearTimeout(timeout);
         timeout = setTimeout(() => {
             resolve(func(...args));
         }, time)
     });
 }

I was searching for a solution to the same problem and came across this thread as well as some others but they had the same problem: if you are trying to do a handleOnChange function and you need the value from an event target, you will get cannot read property value of null or some such error. In my case, I also needed to preserve the context of this inside the debounced function since I'm executing a fluxible action. Here's my solution, it works well for my use case so I'm leaving it here in case anyone comes across this thread:

// at top of file:
var myAction = require('../actions/someAction');

// inside React.createClass({...});

handleOnChange: function (event) {
    var value = event.target.value;
    var doAction = _.curry(this.context.executeAction, 2);

    // only one parameter gets passed into the curried function,
    // so the function passed as the first parameter to _.curry()
    // will not be executed until the second parameter is passed
    // which happens in the next function that is wrapped in _.debounce()
    debouncedOnChange(doAction(myAction), value);
},

debouncedOnChange: _.debounce(function(action, value) {
    action(value);
}, 300)

有一个使用react钩子的简单方法。

步骤1:定义一个状态来维护搜索的文本

const [searchTerm, setSearchTerm] = useState('')

步骤2:使用useEffect捕获搜索Term中的任何变化

useEffect(() => {
  const delayDebounceFn = setTimeout(() => {
    if (searchTerm) {
      // write your logic here
    }
  }, 400)

  return () => clearTimeout(delayDebounceFn)
}, [searchTerm])

步骤3:编写一个函数来处理输入更改

function handleInputChange(value) {
  if (value) {
    setSearchTerm(value)
  }
}

就这些!在需要时调用此方法

与其在debounce()中包装handleOnChange,不如在debounce()中包装回调函数中的ajax调用,从而不破坏事件对象。就像这样:

handleOnChange: function (event) {
   debounce(
     $.ajax({})
  , 250);
}

我们需要将setter传递给debpublished方法:

以下是StackBlitz的一个例子:

import React from "react";
import debounce from "lodash/debounce";

export default function App() {
  const [state, setState] = React.useState({
    debouncedLog: ""
  });

  const debouncedLog = React.useCallback(
    debounce((setState, log) => {
      setState(prevState => ({
        ...prevState,
        debouncedLog: log
      }));
    }, 500),
    []
  );

  const onChange = React.useCallback(({ target: { value: log } }) => {
    debouncedLog(setState, log); // passing the setState along...
  }, []);
  return (
    <div>
      <input onChange={onChange} style={{ outline: "1px blue solid" }} />

      <pre>Debounced Value: {state.debouncedLog}</pre>
    </div>
  );
}

祝你好运…