Search code examples
javascriptreactjsecmascript-6lodashdebouncing

Lodash debounce not working in React


it would be best to first look at my code:

import React, { Component } from 'react';
import _ from 'lodash';
import Services from 'Services'; // Webservice calls

export default class componentName extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: this.props.value || null
    }
  }

  onChange(value) {
    this.setState({ value });

    // This doesn't call Services.setValue at all
    _.debounce(() => Services.setValue(value), 1000);
  }

  render() {
    return (
      <div>
        <input 
          onChange={(event, value) => this.onChange(value)}
          value={this.state.value}
        />
      </div>
    )
  }
}

Just a simple input. In the contructor it grabs value from the props (if available) at sets a local state for the component.

Then in the onChange function of the input I update the state and then try to call the webservice endpoint to set the new value with Services.setValue().

What does work is if I set the debounce directly by the onChange of the input like so:

<input 
  value={this.state.value} 
  onChange={_.debounce((event, value) => this.onChange(value), 1000)} 
/>

But then this.setState gets called only every 1000 milliseconds and update the view. So typing in a textfield ends up looking weird since what you typed only shows a second later.

What do I do in a situation like this?


Solution

  • The problem occurs because you aren't calling the debounce function, you could do in the following manner

    export default class componentName extends Component {
      constructor(props) {
        super(props);
        this.state = {
          value: this.props.value || null
        }
        this.servicesValue = _.debounce(this.servicesValue, 1000);
      }
    
      onChange(value) {
        this.setState({ value });
        this.servicesValue(value);
      }
      servicesValue = (value) => {
          Services.setValue(value)
      }
      render() {
        return (
          <div>
            <input 
              onChange={(event, value) => this.onChange(value)}
              value={this.state.value}
            />
          </div>
        )
      }
    }