DEV Community

Cover image for Updating relative time in UI with Nuxt3
Chris Dermody
Chris Dermody

Posted on

Updating relative time in UI with Nuxt3

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).
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

// /composables/useDateHelpers.ts

import formatDistance from 'date-fns/formatDistance'

export const relativeDate = (date:string) => {
  console.log("date:", date)
  const ticker = useTicker()
  return formatDistance(new Date(date), ticker.value)
}
Enter fullscreen mode Exit fullscreen mode

Notice we're importing our global ticker and using it, making our function's return value reactive in Vue's eyes.

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 -->
Enter fullscreen mode Exit fullscreen mode

The result? We have relative time updating in our UI.

Image description

I think it works quite well.

Any suggestions for improvement? Let me know :)

Also, I'm actively building aihairstyles.com, would love feedback on that too 🙏🏼.

Chris

Top comments (0)