我的一个项目中有一个自定义挂钩,它从 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
挂钩中设置的内容,但这并没有达到我的预期。
在这种情况下,使用
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;