We all have faced this issue one or many times. We need an API call, but not in every refresh or rendering of the component. You cannot just put it in local storage and forget about it because there is a good chance it will get updated sometimes. In this kind of case, what I do is I still use the local storage but use it as a times cache storage. Let me show you how.
Case
In my personal CMS, the one that I use for my blog, media transactions, etc., the menus are generated based on roles and permissions. Though it's super important, there is an API call to get the menu item every time the component renders (change of page). Side note: it is built on larvae 11 with inertia and reactivity. If you have some free time, check it out (https://github.com/msamgan/msamgan.dev)
Using local storage as cache storage
To achieve that, all we have to do is add a timestamp with the data we are storing in the local storage. This will serve as our comparison base for the old data and when to refresh.
localStorage.setItem(
'menu',
JSON.stringify({
menu: response.data,
timestamp: new Date().getTime(), // timestamp in epoch format
}),
)
Now, before hitting the API, we will check if the data we have is older than an hour, if not, then we use the data from the local storage Otherwise, we hit the API, using the new data, and update our cache.
let localStorageData = localStorage.getItem('menu')
if (localStorageData) {
localStorageData = JSON.parse(localStorageData)
// If the data is less than an hour old, use it (cacheDuration = 3600000)
if (localStorageData.timestamp > new Date().getTime() - cacheDuration) {
setMenuItems(localStorageData.menu)
return
}
}
The entire code block will look something like this
const [menuItems, setMenuItems] = useState([])
const getMenus = () => {
let localStorageData = localStorage.getItem('menu')
if (localStorageData) {
localStorageData = JSON.parse(localStorageData)
// If the data is less than an hour old, use it
if (localStorageData.timestamp > new Date().getTime() - cacheDuration) {
setMenuItems(localStorageData.menu)
return
}
}
axios
.get(services.menu)
.then((response) => {
setMenuItems(response.data)
localStorage.setItem(
'menu',
JSON.stringify({
menu: response.data,
timestamp: new Date().getTime(),
}),
)
})
.catch((error) => {
// console.log(error)
})
}
Feel free to suggest any other performance-enhancing approach.