I have a Custom Hook similarly with the below:
import { useEffect, useState } from 'react';
import axios from 'axios';
const myCustomHook = () => {
const [countries, setCountries] = useState([]);
const [isLoading, setLoading] = useState(true);
useEffect(() => {
(async () =>
await axios
.get("MY_API/countries")
.then(response => setCountries(response.data))
.finally(() => setLoading(false)))();
}, []);
return countries;
};
export default myCustomHook;
The hook works great but I am using it in three different areas of my application despite the fact that all the countries are the same wherever the hook is used.
Is there a good pattern to call the axios request just once instead of three times?
EDIT - Final Code After Solution
import { useEffect, useState } from 'react';
import axios from 'axios';
let fakeCache = {
alreadyCalled: false,
countries: []
};
const myCustomHook = (forceUpdate = false) => {
const [isLoading, setLoading] = useState(true);
if (!fakeCache.alreadyCalled || forceUpdate) {
fakeCache.alreadyCalled = true;
(async () =>
await axios
.get("MY_API/countries")
.then(response => setCountries(response.data))
.finally(() => setLoading(false)))();
}
return countries;
};
export default myCustomHook;
One solution to this would be to introduce a custom "cacheing layer" (between your hook and the axios request) that:
countries data returned from the first successful request and,There are a number of ways this could be implemented - one possibility would be to define a getCountries() function that implements that cacheing logic in a separate module, and then call that function from your hook:
countries.js
import axios from 'axios';
// Module scoped variable that holds cache data
let cachedData = undefined;
// Example function wraps network request with cacheing layer
export const getCountries = async() => {
// We expect the data for countries to be an array. If cachedData
// is not an array, attempts to populate the cache with data
if (!Array.isArray(cachedData)) {
const response = await axios.get("MY_API/countries");
// Populate the cache with data returned from request
cachedData = response.data;
}
return cachedData;
}
myCustomHook.js
import { useEffect, useState } from 'react';
import { getCountries } from "/countries";
const myCustomHook = () => {
const [countries, setCountries] = useState([]);
const [isLoading, setLoading] = useState(true);
useEffect(() => {
(async() => {
try {
setLoading(true);
// Update hook state with countries data (cached or fresh)
setCountries(await getCountries());
} finally {
setLoading(false)
}
}, []);
});
}
export default myCustomHook;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With