如何在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
  }
});

当前回答

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

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

其他回答

你也可以使用自己编写的mixin,就像这样:

var DebounceMixin = {
  debounce: function(func, time, immediate) {
    var timeout = this.debouncedTimeout;
    if (!timeout) {
      if (immediate) func();
      this.debouncedTimeout = setTimeout(function() {
        if (!immediate) func();
        this.debouncedTimeout = void 0;
      }.bind(this), time);
    }
  }
};

然后像这样在你的组件中使用它:

var MyComponent = React.createClass({
  mixins: [DebounceMixin],
  handleClick: function(e) {
    this.debounce(function() {
      this.setState({
        buttonClicked: true
      });
    }.bind(this), 500, true);
  },
  render: function() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
});

2019:使用“useCallback”反应钩子

在尝试了许多不同的方法之后,我发现使用useCallback是解决在onChange事件中使用debounce的多次调用问题的最简单和最有效的方法。

根据Hooks API文档,

useCallback返回回调的一个记忆版本,只有当其中一个依赖项发生变化时才会发生变化。

将空数组作为依赖项传递可以确保只调用一次回调。下面是一个简单的实现:

import React, { useCallback } from "react";
import { debounce } from "lodash";

const handler = useCallback(debounce(someFunction, 2000), []);
    
const onChange = (event) => {
    // perform any event related action here
    
    handler();
 };

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>
    </>
  )
}

如果你只需要从事件对象中获取DOM输入元素,解决方案就简单多了——只需要使用ref。注意,这需要下划线:

class Item extends React.Component {
    constructor(props) {
        super(props);
        this.saveTitle = _.throttle(this.saveTitle.bind(this), 1000);
    }
    saveTitle(){
        let val = this.inputTitle.value;
        // make the ajax call
    }
    render() {
        return <input 
                    ref={ el => this.inputTitle = el } 
                    type="text" 
                    defaultValue={this.props.title} 
                    onChange={this.saveTitle} />
    }
}

有点晚了,但应该有帮助。 创建这个类(它是用typescript写的,但是很容易转换成javascript)

export class debouncedMethod<T>{
  constructor(method:T, debounceTime:number){
    this._method = method;
    this._debounceTime = debounceTime;
  }
  private _method:T;
  private _timeout:number;
  private _debounceTime:number;
  public invoke:T = ((...args:any[])=>{
    this._timeout && window.clearTimeout(this._timeout);
    this._timeout = window.setTimeout(()=>{
      (this._method as any)(...args);
    },this._debounceTime);
  }) as any;
}

要使用

var foo = new debouncedMethod((name,age)=>{
 console.log(name,age);
},500);
foo.invoke("john",31);