Updating relative time in UI with Nuxt3
Updating dynamic time value in UI with Nuxt3 and date-fns
I bumped into this problem when working on a side project - aihairstyles.com. When users generate a new set of styles, I want to show them when that set was generated, relative to now. I also want that time to update dynamically as time goes on, without the need for them to refresh the page. Finally, I want to use this logic throughout my app in lots of places.
I solved it with a combination of global state, date-fns library and a small plugin I wrote.
1. Create a state variable to hold a "ticker"
In my useState.ts
file, I'm adding a variable that we'll update later via a plugin.
export const useTicker = () => useState<any>('ticker', () => new Date().getTime())
2. Create a plugin to update this ticker at a given interval
// globalTicker.client.ts
export default defineNuxtPlugin(nuxtApp => {
// updating a global ticker in useState that can be used to auto-update times in the UI
const ticker = useTicker()
const TICKER_INTERVAL = 30000; // milliseconds
setInterval(() => {
let newVal = new Date().getTime();
ticker.value = newVal
}, TICKER_INTERVAL);
})
With this plugin, every 30 seconds the ticker will update (30000 milliseconds).
3. Install date-fns library (or a lib of your choosing)
I used to use moment.js, but date-fns is my go-to now as it's smaller and can be tree-shaken. But use whatever makes you happy.
npm install date-fns --save
4. Create a composable that exports a relative time function
As I mentioned, I wanted this logic throughout my app in lots of places, so creating a composable was the way to go.
To do this, I created a file called useDateHelpers.ts
in my /composables
directory.
5. Finally, use the function in our components
Then, in the html, we use this function and pass in the created_date and the global ticker variable. In the code below we have a for-loop that loops over all image sets.
<!-- rest of preview page ) -->
<h2 class="gradient-text-1 text-2xl">
{{preview.data.style}}
</h2>
<p class="text-sm muted mb-3">
{{ relativeDate(preview.data.result_data?.created_at)}} ago
</p>
<!-- rest of preview page -->
The result? We have relative time updating in our UI
Notice the "less than a minute ago" updates to "1 minute ago" as we update the global ticker (see console logs).
Any suggestions for improvement? Let me know :)