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

当前回答

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

祝你好运…

其他回答

不受控制的组件

你可以使用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。

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

});

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

祝你好运…

使用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>

你也可以使用自己编写的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>
    );
  }
});