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

当前回答

使用ES6 CLASS和React 15.x。X & lodash.debounce 我在这里使用React的refs,因为事件在内部失去了这个绑定。

class UserInput extends React.Component { constructor(props) { super(props); this.state = { userInput: "" }; this.updateInput = _.debounce(this.updateInput, 500); } updateInput(userInput) { this.setState({ userInput }); //OrderActions.updateValue(userInput);//do some server stuff } render() { return ( <div> <p> User typed: { this.state.userInput } </p> <input ref = "userValue" onChange = {() => this.updateInput(this.refs.userValue.value) } type = "text" / > </div> ); } } ReactDOM.render( < UserInput / > , document.getElementById('root') ); <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="root"></div>

其他回答

我发现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和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)} />)
  }
}

我们需要将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>
  );
}

祝你好运…

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

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

不受控制的组件

你可以使用event.persist()方法。

下面是一个使用下划线_.debounce()的例子:

var SearchBox = React.createClass({

  componentWillMount: function () {
     this.delayedCallback = _.debounce(function (event) {
       // `event.target` is accessible now
     }, 1000);
  },

  onChange: function (event) {
    event.persist();
    this.delayedCallback(event);
  },

  render: function () {
    return (
      <input type="search" onChange={this.onChange} />
    );
  }

});

编辑:请看这个JSFiddle


控制组件

更新:上面的例子显示了一个不受控制的组件。我一直在使用受控元素,这里是上面的另一个例子,但没有使用event.persist()“欺骗”。

JSFiddle也是可用的。不带下划线的示例

var SearchBox = React.createClass({
    getInitialState: function () {
        return {
            query: this.props.query
        };
    },

    componentWillMount: function () {
       this.handleSearchDebounced = _.debounce(function () {
           this.props.handleSearch.apply(this, [this.state.query]);
       }, 500);
    },

    onChange: function (event) {
      this.setState({query: event.target.value});
      this.handleSearchDebounced();
    },

    render: function () {
      return (
        <input type="search"
               value={this.state.query}
               onChange={this.onChange} />
      );
    }
});


var Search = React.createClass({
    getInitialState: function () {
        return {
            result: this.props.query
        };
    },

    handleSearch: function (query) {
        this.setState({result: query});
    },

    render: function () {
      return (
        <div id="search">
          <SearchBox query={this.state.result}
                     handleSearch={this.handleSearch} />
          <p>You searched for: <strong>{this.state.result}</strong></p>
        </div>
      );
    }
});

React.render(<Search query="Initial query" />, document.body);

编辑:更新示例和JSFiddles到React 0.12

编辑:更新的例子,以解决Sebastien Lorber提出的问题

编辑:更新的jsfiddle不使用下划线和使用纯javascript debounce。