Home > Blockchain >  Lodash throttle not throttling?
Lodash throttle not throttling?

Time:03-22

I'm trying to apply a lodash throttle for the first time.

I know that the throttle has to be applied inside of a useCallback or it will be called every re-render (in my case, with every new keystroke of a user search).

The code I have is valid, and the logic seems to make sense - but the throttle isn't being applied, and so the api call is being made every single keystroke.

Any pointers as to where my logic is failing?

import {
    useEffect,
    useCallback
} from 'react';
import { throttle } from 'lodash';
import { getAllUsers } from '../../../api/api';
import { USER_ROLE } from '../../../types/types'

interface IProps extends Omit<unknown, 'children'> {
    search?: string;
}

const DemoFanManagementTable = ({ search }: IProps): JSX.Element => {

    const getFans = (search?: string) => {
        console.log("getFans ran")
        const fans = getAllUsers({ search }, USER_ROLE.FAN);
        //logs a promise
        console.log("logging fans ", fans)
        return fans;
    }

    //throttledSearch is running every time search changes
    const throttledSearch = useCallback((search?: string) => {
        console.log("throttledSearch ran")
        return throttle(
            //throttle is not throttling, functions run every keystroke
            () => {
                getFans(search), 10000, { leading: true, trailing: true }
            }
        )
    }, [search])

    //useEffect is running every time search changes
    useEffect(() => {
        return throttledSearch(search)
    }, [search]);

    return (
        <div>
            {search}
        </div>
    );
};

export default DemoFanManagementTable;

CodePudding user response:

There are a few problems here, first you have wrapped the hole throttle func in an anonymous function instead of just the first param:

throttle(
  (search: string) => getFans(search),
  1000,
  { leading: true, trailing: true }
)

Second useCallback is not suitable as each time you call it, it's returning a new throttled function.

Third you have passed [search] as a dependency of useCallback so even if it worked as you expected, it would be invalidated each time search changes and not work anyway.

A better choice is useMemo as it keeps the same throttled function across renders.

const throttledSearch = useMemo(
  () =>
    throttle(
      (search: string) => getFans(search),
      10000,
      { leading: true, trailing: true }
    ),
  []
);

useEffect(() => {
  return throttledSearch(search);
}, [search]);

Since getFans takes the same search param you can shorten it to:

const throttledSearch = useMemo(() =>
  throttle(getFans, 10000, { leading: true, trailing: true }),
[]);
  • Related