动态和重复超时后重新计算派生数据(useEffect 和 useState?)

问题描述 投票:0回答:1

我的一个项目中有一个自定义挂钩,它从 API 获取数据,然后返回该数据的过滤子集。 数据中的每个项目都有一个时间戳,用于确定它是否处于活动状态。 现在,我得到了最短的持续时间,直到项目发生变化并在 useEffect 挂钩内的超时内触发重新计算。

我的钩子使用 useState 存储过滤后的数据,并非常明确地管理 useEffect 钩子 (setFilteredData) 内的更改。 我的问题是是否有更好的方法。使用useMemo 来派生filteredData 会更好或更惯用吗? 在这种情况下,我如何触发它在每次计时器更改时重新运行?

这是一个最小的示例,其中包含一些模拟函数来展示问题。

import React from "react";

// Mock functions
const getMillisecondsToNextCalculation = () =>
Math.round(Math.random() * 10000);
const filterData = (data) => data.filter(Math.random() > 0.5);

const useFilteredData = () => {
  const apiData = useQuery("apiData", fetchApiData);
  const [filteredData, setFilteredData] = React.useState(() =>
    filterData(apiData)
  );

  React.useEffect(() => {
    let timeout;

    const recalculateData = () => {
      const delay = getMillisecondsToNextCalculation();
      if (!delay) return;
    
      // Is this a good practice?
      setFilteredData(filterData(apiData));
    
      // Recursively call the function
      timeout = setTimeout(recalculateData, delay);
    };
    
    recalculateData();
    
    return () => {
      clearTimeout(timeout);
    };
  });

  return {
    filteredData,
  };
};

export default useFilteredData;

对此有任何帮助或意见,我们将不胜感激!

我尝试使用

useMemo
并依赖于我在
useEffect
挂钩中设置的内容,但这并没有达到我的预期。

reactjs react-hooks settimeout rtk-query
1个回答
0
投票

在这种情况下,使用

useMemo
导出
filteredData
确实是一种更干净、更惯用的方法。它允许您记住过滤后的数据,并仅在依赖项发生变化时重新计算。然而,在每次计时器更改时触发它可能需要一些不同的方法。

以下是如何重构

useFilteredData
钩子以使用
useMemo
而不是
useState
useEffect
,并确保它在每次计时器更改时重新计算:

import React from "react";

// Mock functions
const getMillisecondsToNextCalculation = () =>
  Math.round(Math.random() * 10000);
const fetchApiData = () => {
  // Mock API data fetching sample without using any api
  return [
    { id: 1, timestamp: new Date() },
    { id: 2, timestamp: new Date() },
    { id: 3, timestamp: new Date() },
  ];
};
const filterData = (data) => data.filter((item) => Math.random() > 0.5);

const useFilteredData = () => {
  const [timer, setTimer] = React.useState(0);
  const apiData = React.useMemo(() => fetchApiData(), [timer]);

  React.useEffect(() => {
    const timeout = setTimeout(() => {
      setTimer(timer + 1);
    }, getMillisecondsToNextCalculation());

    return () => clearTimeout(timeout);
  }, [timer]);

  const filteredData = React.useMemo(() => filterData(apiData), [apiData]);

  return {
    filteredData,
  };
};

export default useFilteredData;
© www.soinside.com 2019 - 2024. All rights reserved.