Search code examples
javascriptreactjsdebouncing

Delaying API calls with debouncing not working in React


I have gone through several posts but, none useful. So, in a small React project which displays all vegetable images. It also has search box which will fetch relevant vegetable card. I'm trying to implement debouncing function but, not working as expected. Please follow the code below.

// useDeounce function called but, doesn't work
let newAllData = useCallback(useDebounce(searchData, 1000), []);

const getAllData = async () => {
    try {
      setLoading(true);
      const { data } = await axios.get(
        "https://mocki.io/v1/ffbc0f6f-342f-459d-93b4-5921f723b50e"
      );
      setLoading(false);
      setNewData(data);
      console.log("NEW DATA", data); // This gets called on every type of text
    } catch (e) {
      setError(e);
      console.log(e);
    }
  };

useEffect(() => {
    getAllData();
  }, []);

  const handleSearch = (value) => {
    const event = value;

    setSearchData(event);
  };

  const allData = useMemo(() => {

    // the variable with debounce -> newAllData is used here
    if (!newAllData) return newData;

    console.log("NEW DATA HERE", newData);
    return (
      newData &&
      newData?.filter(
        (data) =>
          (data.name.toLowerCase() && data.name.toLowerCase()).search(
            newAllData.toLowerCase()
          ) !== -1 ||
          (data.title.toLowerCase() &&
            data.title.toLowerCase().search(newAllData.toLowerCase()) !== -1)
      )
    );
  }, [searchData, newData]);

As you can see from above code, getAllData fetches the data from API and is called in useEffect, allData is a memoized function which will prevent it from re-rendering, but, still on every tpye, API is called, hence with debouncing may reduce the calls and delay it. Please observe debouncing code.

const useDebounce = (val, delay) => {
  const [debValue, setDebValue] = useState(val);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebValue(val);
    }, delay);
    return () => {
      clearTimeout(handler);
    };
  }, [val, delay]);

  return debValue;
};

What could be the appropriate solution. Since, this is the major concern as API calls, may cost performance issue. Any suggestion highly appreciated.

CodeSandbox link: https://codesandbox.io/s/ecstatic-faraday-j85m9n


Solution

  • First of all remove the useCallback that wraps your useDebounce hook. Thats unnecessary.

    let newAllData =useDebounce(searchData, 1000);
    

    Second, update your useMemo dependency array

    
    const allData = useMemo(() => {
    
        // the variable with debounce -> newAllData is used here
        if (!newAllData) return newData;
    
        console.log("NEW DATA HERE", newData);
        return (
          newData &&
          newData?.filter(
            (data) =>
              (data.name.toLowerCase() && data.name.toLowerCase()).search(
                newAllData.toLowerCase()
              ) !== -1 ||
              (data.title.toLowerCase() &&
                data.title.toLowerCase().search(newAllData.toLowerCase()) !== -1)
          )
        );
         // Change the dependency here from [searchData, newData] to [newAllData, newData]
    
      }, [newAllData, newData]);
    

    Everything should work now as expected !