Let's say you've created a web application that, in addition to the rest of its functionality, presents a piece of information to a user that you'd like to only have a certain shelf life on the page. This could be any range of things, from personal information in a temporary note, to a "Quote of the Day" that should expire every evening at midnight, to data being pulled from a rate-limited external API.
There are multiple ways you could go about this as a developer, but a simple and interesting one is to give that piece of information an expiry date, upon which it will self-destruct back into the digital nether from whence it came.
This trick will explore a few different built-in functionalities within the JavaScript language, and will prove to be a versatile tool to modify or inspire other ideas in your applications later on.
For this tutorial, I'm going to use the context of an application I built with React that provides the user with a meditation timer, a focus/pomodoro timer, and a home and landing page featuring the date and time, local weather, and an inspiring quote of the day.
Within this home page, I knew that I wanted to pull in the quote from an external API automatically-- but I encountered an issue where the API was rate limited in order to preserve their bandwidth. I could only make a certain number of calls per hour before my app became temporarily restricted, and the quote disappeared from the page entirely (replace by an unsightly console error!)
I knew I could try and prevent this by only fetching the quote once a day on the server side, but I thought I would use the opportunity to experiment with keeping the fetch on the client side and experimenting with giving the data an expiry date on a visitor-by-visitor basis, as I knew that might benefit me in future applications.
Within this discussion we're going to be using two standardized functionalities of modern web development.
The first of which is an aspect of the Window containing the DOM document of the site:
Window.localStorage
And the second being a built in object of the JavaScript language:
Date()
localStorage is a property that gives you access to a storage object in the document that persists across browser sessions. It can be accessed through your JavaScript code or through the browser console directly.
Date() is an object that represents a single point in time when it is created, measured in the number of milliseconds since January 1st 1970 UTC. This Date() object has a number of built in functions to manipulate it, one of which we'll be making use of in our example.
The bullet-pointed version of what I'm going to be showing is as follows:
- When the home page is loaded, we check the user's localStorage to see if there's already a quote there that has been fetched.
- If there isn't a quote, then we fetch a new quote from the API, save that quote to localStorage, and also run a function to save an expiry date/time along with it for when we want that quote to be replaced.
- If there is a quote, then we compare the current date/time against the expiry date/time (in this case the expiry is the midnight of the same day that the quote was saved to localStorage).
- If the current date/time is before the expiry date/time, then we pull the quote from localStorage and render it on the page.
- If the current date/time is after the expiry date/time, then we clear the localStorage and go back to step 1 and fetch a new quote from the API.
Now let's see this in action in the code!
First off, I'm creating two helper functions that are abstracted out to keep the code clean and DRY.
The first is a function labeled secondsToMidnight() that takes in a Date() object as n and uses the object's built in functions getHours(), getMinutes(), and getSeconds() to find the amount of seconds until midnight of the same day as the Date() object. This might seem a bit confusing, but essentially this is the step that can be modified to find the amount of time anywhere in the future that you'd like to set as an expiry date for your data.
const secondsToMidnight = (n) => {
return (
((24 - n.getHours() - 1) * 60 * 60) + ((60 - n.getMinutes() - 1) * 60) + (60 - n.getSeconds())
)
}
The second helper function is labeled assignQuoteToLocalStorage(), which does 4 things:
- Makes use of a fetch to the API (getQuoteOfTheDay()) to get a quote.
- Creates a Date() object under the variable currentTime and does 3 things with it to create an expiry date/time:
- Use the built in function getTime() to get the current time in milliseconds (the measurement of current time as a distance from January 1st 1970).
- Passes the currentTime date object into the secondsToMidnight(), then multiplies that by 1000 to get the milliseconds until midnight.
- Adds the two numbers together to get a future date/time in milliseconds that equals exactly midnight of the same day.
- Sets both the quote and the expiry to localStorage as key/value pairs in the object.
- Sets the quote to state in React to be rendered on the page (setQuoteOfTheDay()).
const assignQuoteToLocalStorage = () => {
getQuoteOfTheDay()
.then( quote => {
const currentTime = new Date()
const expiry = currentTime.getTime() + (secondsToMidnight(currentTime) * 1000)
localStorage.quote = JSON.stringify(quote)
localStorage.expiry = expiry
setQuoteOfTheDay(quote)
})
}
Now we make use of both of the above helper methods to do the following in our component mounting (happening every time the page is loaded):
if (!!localStorage.quote) {
let quoteExpiry = parseInt(localStorage.getItem("expiry"))
let now = new Date()
if (now.getTime() > quoteExpiry) {
localStorage.removeItem("quote")
localStorage.removeItem("expiry")
assignQuoteToLocalStorage()
} else {
let quote = JSON.parse(localStorage.getItem("quote"))
setQuoteOfTheDay(quote)
}
} else {
assignQuoteToLocalStorage()
}
In our first if statement we're checking to see if there's a quote in the localStorage. If there is, we then pull the expiry date out of localStorage, create a new current Date() object, and compare the two.
We use a nested if statement to check if the current time is after the expiry time. If so, we remove both the quote and the expiry from our localStorage and call our helper function (assignQuoteToLocalStorage()) to fetch a new quote and create a new expiry for it. If the current time is still before the expiry, we pull the quote from localStorage and set it to our state for rendering on the page.
If our first if statement returned false and no quote was found in localStorage, then we call assignQuoteToLocalStorage() and fetch a new quote and assign it and an expiry date to localStorage.
And we're done! While this was all done in the specific context of my application, the same principles hold true anywhere.
You can use a trick like this with JavaScript Date() objects and their associated functions to save expiry times to localStorage or to your database in whatever format you'd like, to create self-destructing pieces of data.
Thanks for reading! Let me know in the comments if you have any questions or suggestions.
Top comments (0)