Delaying API calls with debouncing not working in React.

huangapple go评论51阅读模式
英文:

Delaying API calls with debouncing not working in React

问题

我浏览了几篇帖子,但没有找到有用的信息。在一个小的React项目中,显示所有蔬菜图片。它还有一个搜索框,可以获取相关的蔬菜卡片。我正在尝试实现debouncing函数,但效果不如预期。请查看以下代码。

// useDeounce函数被调用,但不起作用
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); // 这在每种文本类型上都被调用
    } catch (e) {
      setError(e);
      console.log(e);
    }
  };

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

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

    setSearchData(event);
};

const allData = useMemo(() => {
    // 使用debounce的变量-> newAllData 在这里使用
    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]);

正如你从上面的代码看到的,getAllData从API获取数据,并在useEffect中调用,allData是一个被记忆的函数,可以防止重新渲染,但是在每一次输入时,API都被调用,因此通过防抖可以减少调用并延迟它。请观察防抖代码。

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

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

    return debValue;
};

适当的解决方案是什么呢?由于这是主要关注点,因为API调用可能会导致性能问题。非常感谢任何建议。

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

英文:

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

答案1

得分: 1

首先移除包裹你的useDebounce钩子的useCallback,这是不必要的。

let newAllData = useDebounce(searchData, 1000);

其次,更新你的useMemo依赖数组。

const allData = useMemo(() => {

    // 使用防抖的变量 -> 这里使用了newAllData
    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] 更改为 [newAllData, newData]

  }, [newAllData, newData]);

现在一切应该按预期工作!

英文:

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 !

huangapple
  • 本文由 发表于 2023年5月7日 15:11:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76192615.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定