Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lodash debounce not working in React

People also ask

How do you debounce in react?

Here's a simple implementation : import React, { useCallback } from "react"; import { debounce } from "lodash"; const handler = useCallback(debounce(someFunction, 2000), []); const onChange = (event) => { // perform any event related action here handler(); };

How do you debounce from Lodash?

Lodash debounce() method is that debounce function mentioned in point 3. In this case, the timer will start running from the last call of the debouncedLogHi() function. After 1500 milliseconds, the function will run.

How does debounce Lodash work?

Lodash is a package that contains lots of great utility functions. For example, Lodash's debounce function delays invoking a function passed into it. It can help performance in some situations. In this post, we will use debounce to search for a Star Wars character when the user stops typing.

How do you use Lodash debounce in react native?

To use Lodash debounce in a React Native app, we can call debounce with the function we want to debounce. to assign onChangeText to a function that debounce returns which delays setText by 500 milliseconds. And then we set that as the value of the TextInput onChangeText prop.


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

Solution for those who came here because throttle / debounce doesn't work with FunctionComponent - you need to store debounced function via useRef():

export const ComponentName = (value = null) => {
  const [inputValue, setInputValue] = useState(value);

  const setServicesValue = value => Services.setValue(value);

  const setServicesValueDebounced = useRef(_.debounce(setServicesValue, 1000));

  const handleChange = ({ currentTarget: { value } }) => {
    setInputValue(value);
    setServicesValueDebounced.current(value);
  };

  return <input onChange={handleChange} value={inputValue} />;
};

This medium article perfectly explains what happens:

Local variables inside a function expires after every call. Every time the component is re-evaluated, the local variables gets initialized again. Throttle and debounce works using window.setTimeout() behind the scenes. Every time the function component is evaluated, you are registering a fresh setTimeout callback. So we will use useRef() hook as value returned by useRef() does not get re-evaluated every time the functional component is executed. The only inconvenience is that you have to access your stored value via the .current property.

I've created sandbox with tiny lodash.throttle and lodash.debounce packages so you can experiment with both and choose suitable behavior


For a React functional component, debounce does not work by default. You will have to do the following for it to work:

const debouncedFunction= React.useCallback(debounce(functionToCall, 400), []);

useCallback makes use of the function returned by debounce and works as expected. Although, this is a bit more complicated when you want to use state variables inside the debounced function (Which is usually the case).

React.useCallback(debounce(fn, timeInMs), [])

The second argument for React.useCallback is for dependencies. If you would like to use a state or prop variable in the debounced function, by default, it uses an an old version of the state variable which will cause your function to use the historical value of the variable which is not what you need. To solve this issue, you will have to include the state variable like you do in React.useEffect like this:

React.useCallback(debounce(fn, timeInMs), [stateVariable1, stateVariable2])

This implementation might solve your purpose. But you will notice that the debounced function is called every time the state variables (stateVariable1, stateVariable2) passed as dependencies change. Which might not be what you need especially if using a controlled component like an input field.

The best solution I realized is to put some time to change the functional component to a class based component and use the following implementation:

constructor(props)
    {
        super();
        this.state = {...};
        this.functionToCall= debounce(this.functionToCall.bind(this), 400, {'leading': true});
    }