Perform debounce in React.js

前端 未结 30 1473
礼貌的吻别
礼貌的吻别 2020-11-22 04:11

How do you perform debounce in React.js?

I want to debounce the handleOnChange.

I tried with debounce(this.handleOnChange, 200) but it doesn\'t

相关标签:
30条回答
  • 2020-11-22 04:51

    Uncontrolled Components

    You can use the event.persist() method.

    An example follows using underscore's _.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} />
        );
      }
    
    });
    

    Edit: See this JSFiddle


    Controlled Components

    Update: the example above shows an uncontrolled component. I use controlled elements all the time so here's another example of the above, but without using the event.persist() "trickery".

    A JSFiddle is available as well. Example without underscore

    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);
    

    Edit: updated examples and JSFiddles to React 0.12

    Edit: updated examples to address the issue raised by Sebastien Lorber

    Edit: updated with jsfiddle that does not use underscore and uses plain javascript debounce.

    0 讨论(0)
  • 2020-11-22 04:52

    FYI

    Here is another PoC implementation:

    • without any libraries (e.g. lodash) for debouncing
    • using React Hooks API

    I hope it helps :)

    import React, { useState, useEffect, ChangeEvent } from 'react';
    
    export default function DebouncedSearchBox({
      inputType,
      handleSearch,
      placeholder,
      debounceInterval,
    }: {
      inputType?: string;
      handleSearch: (q: string) => void;
      placeholder: string;
      debounceInterval: number;
    }) {
      const [query, setQuery] = useState<string>('');
      const [timer, setTimer] = useState<NodeJS.Timer | undefined>();
    
      useEffect(() => {
        if (timer) {
          clearTimeout(timer);
        }
        setTimer(setTimeout(() => {
          handleSearch(query);
        }, debounceInterval));
      }, [query]);
    
      const handleOnChange = (e: ChangeEvent<HTMLInputElement>): void => {
        setQuery(e.target.value);
      };
    
      return (
        <input
          type={inputType || 'text'}
          className="form-control"
          placeholder={placeholder}
          value={query}
          onChange={handleOnChange}
        />
      );
    }
    
    0 讨论(0)
  • 2020-11-22 04:52

    you can use tlence tlence

    function log(server) {
      console.log('connecting to', server);
    }
    
    const debounceLog = debounce(log, 5000);
    // just run last call to 5s
    debounceLog('local');
    debounceLog('local');
    debounceLog('local');
    debounceLog('local');
    debounceLog('local');
    debounceLog('local');
    
    0 讨论(0)
  • 2020-11-22 04:53

    If you are using redux you can do this in a very elegant way with middleware. You can define a Debounce middleware as:

    var timeout;
    export default store => next => action => {
      const { meta = {} } = action;
      if(meta.debounce){
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          next(action)
        }, meta.debounce)
      }else{
        next(action)
      }
    }
    

    You can then add debouncing to action creators, such as:

    export default debouncedAction = (payload) => ({
      type : 'DEBOUNCED_ACTION',
      payload : payload,
      meta : {debounce : 300}
    }
    

    There's actually already middleware you can get off npm to do this for you.

    0 讨论(0)
  • 2020-11-22 04:53

    Using ES6 CLASS and React 15.x.x & lodash.debounce Im using React's refs here since event losses the this bind internally.

    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>

    0 讨论(0)
  • 2020-11-22 04:53

    There's a use-debounce package that you can use with ReactJS hooks.

    From package's README:

    import { useDebounce } from 'use-debounce';
    
    export default function Input() {
      const [text, setText] = useState('Hello');
      const [value] = useDebounce(text, 1000);
    
      return (
        <div>
          <input
            defaultValue={'Hello'}
            onChange={(e) => {
              setText(e.target.value);
            }}
          />
          <p>Actual value: {text}</p>
          <p>Debounce value: {value}</p>
        </div>
      );
    }
    

    As you can see from the example above, it is set up to update the variable value only once every second (1000 milliseconds).

    0 讨论(0)
提交回复
热议问题