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

当前回答

我在这个问题下找不到任何答案,提到我正在使用的方法,所以只想在这里提供一个替代解决方案,我认为这是最适合我的用例。

如果您正在使用流行的react钩子工具包库react-use,那么有一个名为useDebounce()的实用工具钩子,它以一种相当优雅的方式实现了谴责逻辑。

const [query, setQuery] = useState('');

useDebounce(
  () => {
    emitYourOnDebouncedSearchEvent(query);
  },
  2000,
  [query]
);

return <input onChange={({ currentTarget }) => setQuery(currentTarget.value)} />

有关详细信息,请直接检查库的github页面。

https://github.com/streamich/react-use/blob/master/docs/useDebounce.md

其他回答

有点晚了,但应该有帮助。 创建这个类(它是用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);

Julen的解决方案有点难以阅读,这里有更清晰和准确的反应代码,供那些根据标题而不是问题的微小细节绊倒他的人使用。

Tl;dr版本:当你要更新到观察者发送调用一个调度方法,反过来实际上会通知观察者(或执行ajax等)

使用示例组件jsfiddle完成jsfiddle

var InputField = React.createClass({

    getDefaultProps: function () {
        return {
            initialValue: '',
            onChange: null
        };
    },

    getInitialState: function () {
        return {
            value: this.props.initialValue
        };
    },

    render: function () {
        var state = this.state;
        return (
            <input type="text"
                   value={state.value}
                   onChange={this.onVolatileChange} />
        );
    },

    onVolatileChange: function (event) {
        this.setState({ 
            value: event.target.value 
        });

        this.scheduleChange();
    },

    scheduleChange: _.debounce(function () {
        this.onChange();
    }, 250),

    onChange: function () {
        var props = this.props;
        if (props.onChange != null) {
            props.onChange.call(this, this.state.value)
        }
    },

});
/**
 * Returns a function with the same signature of input `callback` (but without an output) that if called, smartly
 * executes the `callback` in a debounced way.<br>
 * There is no `delay` (to execute the `callback`) in the self-delayed tries (try = calling debounced callback). It
 * will defer **only** subsequent tries (that are earlier than a minimum timeout (`delay` ms) after the latest
 * execution). It also **cancels stale tries** (that have been obsoleted because of creation of newer tries during the
 * same timeout).<br>
 * The timeout won't be expanded! So **the subsequent execution won't be deferred more than `delay`**, at all.
 * @param {Function} callback
 * @param {number} [delay=167] Defaults to `167` that is equal to "10 frames at 60 Hz" (`10 * (1000 / 60) ~= 167 ms`)
 * @return {Function}
 */
export function smartDebounce (callback, delay = 167) {
  let minNextExecTime = 0
  let timeoutId

  function debounced (...args) {
    const now = new Date().getTime()
    if (now > minNextExecTime) { // execute immediately
      minNextExecTime = now + delay // there would be at least `delay` ms between ...
      callback.apply(this, args) // ... two consecutive executions
      return
    }
    // schedule the execution:
    clearTimeout(timeoutId) // unset possible previous scheduling
    timeoutId = setTimeout( // set new scheduling
      () => {
        minNextExecTime = now + delay // there would be at least `delay` ms between ...
        callback.apply(this, args) // ... two consecutive executions
      },
      minNextExecTime - now, // 0 <= timeout <= `delay` ... (`minNextExecTime` <= `now` + `delay`)
    )
  }

  debounced.clear = clearTimeout.bind(null, timeoutId)

  return debounced
}
/**
 * Like React's `useCallback`, but will {@link smartDebounce smartly debounce} future executions.
 * @param {Function} callback
 * @param {[]} deps
 * @param {number} [delay=167] - Defaults to `167` that is equal to "10 frames at 60 Hz" (`10 * (1000 / 60) ~= 167 ms`)
 */
export const useDebounced = (callback, deps, delay = 167) =>
  useMemo(() => smartDebounce(callback, delay), [...deps, delay])

你可以用沉默

function log(server) {
  console.log('connecting to', server);
}

const debounceLog = debounce(log, 5000);
// just run last call to 5s
debounceLog('local');
debounceLog('local');
debounceLog('local');
debounceLog('local');
debounceLog('local');
debounceLog('local');

一个漂亮干净的解决方案,不需要任何外部依赖:

与React挂钩反弹

它使用了一个自定义加上useEffect React钩子和setTimeout / clearTimeout方法。