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

当前回答

这里已经有很多好的信息了,但为了简洁。这对我很有用……

import React, {Component} from 'react';
import _ from 'lodash';

class MyComponent extends Component{
      constructor(props){
        super(props);
        this.handleChange = _.debounce(this.handleChange.bind(this),700);
      }; 

其他回答

/**
 * 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])

对于throttle或debounce,最好的方法是创建一个函数生成器,这样你就可以在任何地方使用它,例如:

  updateUserProfileField(fieldName) {
    const handler = throttle(value => {
      console.log(fieldName, value);
    }, 400);
    return evt => handler(evt.target.value.trim());
  }

在你的渲染方法中,你可以这样做:

<input onChange={this.updateUserProfileField("givenName").bind(this)}/>

updateUserProfileField方法将在每次调用它时创建一个单独的函数。

注意不要尝试直接返回处理程序,例如,这将不起作用:

 updateUserProfileField(fieldName) {
    return evt => throttle(value => {
      console.log(fieldName, value);
    }, 400)(evt.target.value.trim());
  }

为什么这将不会工作的原因,因为这将生成一个新的油门函数每次事件调用而不是使用相同的油门函数,所以基本上油门将是无用的;)

此外,如果你使用debounce或throttle,你不需要setTimeout或clearTimeout,这实际上是我们使用它们的原因: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)
     });
 }

如果我们有兴趣在react.js中使用epic.js,我们可以在epic.js库中使用debounceTime rxjs/操作符。因此,我们可以在epic.js的帮助下,在react.js中使用可观察对象,而不是使用回调。

只是最近react和lodash的另一个变体。

class Filter extends Component {
  static propTypes = {
    text: PropTypes.string.isRequired,
    onChange: PropTypes.func.isRequired
  }

  state = {
    initialText: '',
    text: ''
  }

  constructor (props) {
    super(props)

    this.setText = this.setText.bind(this)
    this.onChange = _.fp.debounce(500)(this.onChange.bind(this))
  }

  static getDerivedStateFromProps (nextProps, prevState) {
    const { text } = nextProps

    if (text !== prevState.initialText) {
      return { initialText: text, text }
    }

    return null
  }

  setText (text) {
    this.setState({ text })
    this.onChange(text)
  }

  onChange (text) {
    this.props.onChange(text)
  }

  render () {
    return (<input value={this.state.text} onChange={(event) => this.setText(event.target.value)} />)
  }
}