Search code examples
javascriptreactjslodash

create a debounced function that delays invoking func when searching


I create a debounced function that delays invoking func getTodo. It writes letters to the input, but nothing happens. In the network tab, also zero requests. Without debounce, the search works.

import _, {debounce} from 'lodash';

class App extends Component {
  constructor (props) {
    super(props);
    this.state = {
      todos: [],
    }
  }

  search = (query) => {
    debounce(() =>  this.getTodo(query), 1000)
  }

  getTodo = (query) => {
    axios({
       url: `/api/v1/todos/{query}`,
       method: "GET"
    })
    .then(res => {  
        this.setState({
            todos: res.data
        });
    })
    .catch(error => {
      console.log(error);
    }) 

  render () {

    return (
        <input onChange={this.search} />    
    )
  }
}

Solution

  • Debounce is a higher order function that takes another function at wraps it. For debounce to work you need to continuously invoke the new function returned by the debounce (the debounced function). Whenever the debounced function is called, it delays calling the wrapped function by the wait time. If it's called again during the wait time window, the execution of the wrapped function is delayed again by the same wait time and so on. If the wait time ends, and the function wasn't called again during that time, the wrapped function is called.

    You are creating the debounced function, and you don't invoke it, and this is why nothing happens. The answer by @iagowp's recreates the function all the time, which means that it acts like a setTimeout with a delay of 1000ms, and not as a debounced function.

    To use debounce correctly, wrap your getTodo function with debounce. This will return a new wrapped function, which you invoke as your onChange handler:

    getTodo = debounce((query) => {
      axios({
          url: `/api/v1/todos/{query}`,
          method: "GET"
        })
        .then(res => {
          this.setState({
            todos: res.data
          });
        })
        .catch(error => {
          console.log(error);
        })
    }, 1000);
    

    If you want to separate the handler from the server call, you can wrap the search method instead:

    search = debounce((query) => this.getTodo(query), 1000);