Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debounce triggering multiple times in react

I am struggling with what's suppose to be a simple debounce. But somehow instead of waiting and triggering once, it waits but triggers all the events one by one until the last one.

It's part of the react component. Here is the code :

import debounce from "lodash.debounce";
(...)

export default () => {
    const { filter, updateFilter } = useContext(AppContext);
    const [searchString, setSearchString] = useState(filter.searchString);

    const changeFilter = value => {
        console.log(value);
    };

    const changeFilterDebounced = debounce(changeFilter, 3000, true);

    const handleChange = e => {
        let { value } = e.target;
        setSearchString(value);
        changeFilterDebounced(value);
};
(...)

So if I type something like "abc" in my input that gets the

onChange={handleChange}

it waits a bit (the three seconds) and then will show three successive console.log with values "a", "ab", "abc". My expectation was for it to trigger only once with "abc". I am wondering where I am missing something. Tried to add true as the third argument but didn't change anything and I am also creating a specific function with the debounce not to create a new debounce each time as mentioned in other posts.

Thanks for your help.

like image 486
Ivo Avatar asked Jul 10 '26 08:07

Ivo


2 Answers

The debounced function is getting recreated on every re-render.

You will need to wrap it in useCallback which will hold the same reference unless one of the variables inside the dependencies array change

const changeFilterDebounced = useCallback(
  debounce(value => console.log(value), 3000, true),
  []
)
like image 192
Asaf Aviv Avatar answered Jul 11 '26 21:07

Asaf Aviv


As you're using a functional component, all the functions defined will be reinitialized on each render, ie creating a new debounced function each time.

The possible workaround is to use useMemo and useCallback along with it so that the reference of function does not change on each render.

const changeFilterDebounced = debounce(changeFilter, 3000, true);

can be changed into:

const changeFilterDebounced = useMemo(() => debounce(changeFilter, 3000, true), [handleChange]);

and wrap handleChange with useCallback like:

const handleChange = useCallback(e => {
    let { value } = e.target;
    setSearchString(value);
    changeFilterDebounced(value);
}, []);

The empty dependency array as the second argument of useCallback was provided, so that its ref will be the same till the component unmounts.

Hope this helps.

like image 33
Vishnu Avatar answered Jul 11 '26 21:07

Vishnu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!