I have a mystery. Consider the following custom React hook that fetches data by time period and stores the results in a Map
:
export function useDataByPeriod(dateRanges: PeriodFilter[]) {
const isMounted = useMountedState();
const [data, setData] = useState(
new Map(
dateRanges.map(dateRange => [
dateRange,
makeAsyncIsLoading({ isLoading: false }) as AsyncState<MyData[]>
])
)
);
const updateData = useCallback(
(period: PeriodFilter, asyncState: AsyncState<MyData[]>) => {
const isSafeToSetData = isMounted === undefined || (isMounted !== undefined && isMounted());
if (isSafeToSetData) {
setData(new Map(data.set(period, asyncState)));
}
},
[setData, data, isMounted]
);
useEffect(() => {
if (dateRanges.length === 0) {
return;
}
const loadData = () => {
const client = makeClient();
dateRanges.map(dateRange => {
updateData(dateRange, makeAsyncIsLoading({ isLoading: true }));
return client
.getData(dateRange.dateFrom, dateRange.dateTo)
.then(periodData => {
updateData(dateRange, makeAsyncData(periodData));
})
.catch(error => {
const errorString = `Problem fetching ${dateRange.displayPeriod} (${dateRange.dateFrom} - ${dateRange.dateTo})`;
console.error(errorString, error);
updateData(dateRange, makeAsyncError(errorString));
});
});
};
loadData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dateRanges /*, updateData - for some reason when included this triggers infinite renders */]);
return data;
}
The useEffect
is being repeatedly triggered when updateData
is added as a dependency. If I exclude it as a dependency then everything works / behaves as expected but eslint
complains I'm violating react-hooks/exhaustive-deps
.
Given updateData
has been useCallback
-ed I'm at a loss to understand why it should repeatedly trigger renders. Can anyone shed any light please?
react-hooks/exhaustive-deps
issue in a different place? – Gent