Cache your fetcher in useSWR with useCallback.
I found a way that caches the fetcher in useSWR using useCallback in the Gitroom source code.
The above image is from platform-analytics/render.analytics.tsx. Let’s try to understand this code snippet.
we’ll explore how to optimize data fetching in your React applications using the useCallback
hook in combination with useSWR
. We'll break down the provided code snippet, explain why caching your fetcher function is important.
Understanding the Code
Let’s dive into the code step by step:
const load = useCallback(async () => {
setLoading(true);
const load = (
await fetch(`/analytics/${integration.id}?date=${date}`)
).json();
setLoading(false);
return load;
}, [integration, date]);
Here, we’re defining an asynchronous function load
inside a useCallback
hook. This function fetches data from a specified endpoint and handles the loading state. The useCallback
hook ensures that this function is memoized and only recreated when the dependencies (integration
and date
) change.
Next, we use useSWR
to manage the data fetching:
const { data } = useSWR(`/analytics-${integration?.id}-${date}`, load, {
refreshInterval: 0,
refreshWhenHidden: false,
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
refreshWhenOffline: false,
revalidateOnMount: true,
});
Here, useSWR
is configured with a key (/analytics-${integration?.id}-${date}
) and our memoized load
function. The configuration options control the revalidation behavior of the data.
How useCallback
Prevents Unnecessary Re-fetches
To understand how useCallback
prevents unnecessary re-fetches, we need to delve into how React handles function references and how useSWR
works.
Function References in React
In React, every time a component re-renders, all functions defined within it are recreated. This means that without useCallback
, a new instance of your load
function would be created on every render.

Impact on useSWR
useSWR
is a data fetching library for React. It uses a key to identify the data and a fetcher function to fetch it. useSWR
relies on the stability of the fetcher function reference. If the reference changes, useSWR
might interpret this as a signal that the data needs to be refetched, even if the actual logic of the fetcher hasn't changed.
Here’s a detailed explanation:
- Without
useCallback
:
const load = async () => {
setLoading(true);
const load = (
await fetch(`/analytics/${integration.id}?date=${date}`)
).json();
setLoading(false);
return load;
};
const { data } = useSWR(`/analytics-${integration?.id}-${date}`, load, {
refreshInterval: 0,
refreshWhenHidden: false,
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
refreshWhenOffline: false,
revalidateOnMount: true,
});
In this case, every render creates a new load
function. useSWR
sees a different function reference each time, which can lead to unnecessary re-fetches even when integration
and date
haven't changed.
With useCallback
:
const load = useCallback(async () => {
setLoading(true);
const load = (
await fetch(`/analytics/${integration.id}?date=${date}`)
).json();
setLoading(false);
return load;
}, [integration, date]);
const { data } = useSWR(`/analytics-${integration?.id}-${date}`, load, {
refreshInterval: 0,
refreshWhenHidden: false,
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
refreshWhenOffline: false,
revalidateOnMount: true,
});
By wrapping the load
function in useCallback
, we ensure that it is only recreated when its dependencies (integration
and date
) change. This stability in the function reference tells useSWR
that the fetcher function hasn't changed unless integration
or date
changes, thus preventing unnecessary re-fetches.
Get free courses inspired by the best practices used in open source.
About me:
Website: https://ramunarasinga.com/
Linkedin: https://www.linkedin.com/in/ramu-narasinga-189361128/
Github: https://github.com/Ramu-Narasinga
Email: ramu.narasinga@gmail.com
Learn the best practices used in open source.