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

当前回答

class UserListComponent extends Component {
    constructor(props) {
        super(props);
        this.searchHandler = this.keyUpHandler.bind(this);
        this.getData = this.getData.bind(this);
        this.magicSearch = this.magicSearch.bind(this,500);
    }
    getData = (event) => {
        console.log(event.target.value);
    }
    magicSearch = function (fn, d) {
        let timer;
        return function () {
            let context = this;
            clearTimeout(timer);
            timer = setTimeout(() => {
                fn.apply(context, arguments)
            }, d);
        }
    }
    keyUpHandler = this.magicSearch(this.getData, 500);
    render() {
        return (
             <input type="text" placeholder="Search" onKeyUp={this.searchHandler} />
        )
    }
}

其他回答

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

});

如果你不喜欢添加lodash或任何其他包:

import React, { useState, useRef } from "react";

function DebouncedInput() {
  const [isRefetching, setIsRefetching] = useState(false);
  const [searchTerm, setSearchTerm] = useState("");
  const previousSearchTermRef = useRef("");

  function setDebouncedSearchTerm(value) {
    setIsRefetching(true);
    setSearchTerm(value);
    previousSearchTermRef.current = value;
    setTimeout(async () => {
      if (previousSearchTermRef.current === value) {
        try {
          // await refetch();
        } finally {
          setIsRefetching(false);
        }
      }
    }, 500);
  }

  return (
    <input
      value={searchTerm}
      onChange={(event) => setDebouncedSearchTerm(event.target.value)}
    />
  );
}

如果你只需要在一个按钮中执行一个请求数据的debounce,提供的代码可能对你有帮助:

创建一个函数,以防止在请求为真或假时使用默认的条件语句 实现useState钩子和useEffect钩子

const PageOne = () => {
 const [requesting, setRequesting] = useState(false);

  useEffect(() => {
    return () => {
      setRequesting(false);
    };
  }, [requesting]);

  const onDebounce = (e) => {
    if (requesting === true) {
      e.preventDefault();
    }
    // ACTIONS
    setLoading(true);
  };

 return (
  <div>
    
    <button onClick={onDebounce}>Requesting data</button>
  </div>
 )
}

只是最近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)} />)
  }
}

I was searching for a solution to the same problem and came across this thread as well as some others but they had the same problem: if you are trying to do a handleOnChange function and you need the value from an event target, you will get cannot read property value of null or some such error. In my case, I also needed to preserve the context of this inside the debounced function since I'm executing a fluxible action. Here's my solution, it works well for my use case so I'm leaving it here in case anyone comes across this thread:

// at top of file:
var myAction = require('../actions/someAction');

// inside React.createClass({...});

handleOnChange: function (event) {
    var value = event.target.value;
    var doAction = _.curry(this.context.executeAction, 2);

    // only one parameter gets passed into the curried function,
    // so the function passed as the first parameter to _.curry()
    // will not be executed until the second parameter is passed
    // which happens in the next function that is wrapped in _.debounce()
    debouncedOnChange(doAction(myAction), value);
},

debouncedOnChange: _.debounce(function(action, value) {
    action(value);
}, 300)