如何在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.js中使用epic.js,我们可以在epic.js库中使用debounceTime rxjs/操作符。因此,我们可以在epic.js的帮助下,在react.js中使用可观察对象,而不是使用回调。

其他回答

对于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

我发现Justin Tulk的这篇文章很有帮助。在经过几次尝试后,人们会认为这是react/redux更正式的方式,结果显示它失败了,因为react的合成事件池。然后,他的解决方案使用一些内部状态来跟踪在输入中更改/输入的值,在setState之后使用一个回调,调用一个throttled/ deboundredux动作,实时显示一些结果。

import React, {Component} from 'react'
import TextField from 'material-ui/TextField'
import { debounce } from 'lodash'

class TableSearch extends Component {

  constructor(props){
    super(props)

    this.state = {
        value: props.value
    }

    this.changeSearch = debounce(this.props.changeSearch, 250)
  }

  handleChange = (e) => {
    const val = e.target.value

    this.setState({ value: val }, () => {
      this.changeSearch(val)
    })
  }

  render() {

    return (
        <TextField
            className = {styles.field}
            onChange = {this.handleChange}
            value = {this.props.value}
        />
    )
  }
}

有一个使用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)
  }
}

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

这里有一个工作的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)
     });
 }

今天遇到了这个问题。使用setTimeout和clearTimeout解决。

我将给出一个你可以适应的例子:

import React, { Component } from 'react'

const DEBOUNCE_TIME = 500

class PlacesAutocomplete extends Component {
  debounceTimer = null;

  onChangeHandler = (event) => {
    // Clear the last registered timer for the function
    clearTimeout(this.debounceTimer);

    // Set a new timer
    this.debounceTimer = setTimeout(
      // Bind the callback function to pass the current input value as arg
      this.getSuggestions.bind(null, event.target.value), 
      DEBOUNCE_TIME
    )
  }

  // The function that is being debounced
  getSuggestions = (searchTerm) => {
    console.log(searchTerm)
  }

  render() {
    return (
      <input type="text" onChange={this.onChangeHandler} />
    )
  }
}

export default PlacesAutocomplete

你也可以在它自己的函数组件中重构它:

import React from 'react'

function DebouncedInput({ debounceTime, callback}) {
  let debounceTimer = null
  return (
    <input type="text" onChange={(event) => {
      clearTimeout(debounceTimer);

      debounceTimer = setTimeout(
        callback.bind(null, event.target.value), 
        debounceTime
      )
    }} />
  )
}

export default DebouncedInput

像这样使用它:

import React, { Component } from 'react'
import DebouncedInput from '../DebouncedInput';

class PlacesAutocomplete extends Component {
  debounceTimer = null;

  getSuggestions = (searchTerm) => {
    console.log(searchTerm)
  }

  render() {
    return (
      <DebouncedInput debounceTime={500} callback={this.getSuggestions} />
    )
  }
}

export default PlacesAutocomplete