Skip to content

Instantly share code, notes, and snippets.

@meduzen
Last active February 19, 2026 13:15
Show Gist options
  • Select an option

  • Save meduzen/6ee1cd0d8a3ce589862801e9ddfb4ce9 to your computer and use it in GitHub Desktop.

Select an option

Save meduzen/6ee1cd0d8a3ce589862801e9ddfb4ce9 to your computer and use it in GitHub Desktop.
Approach for an updated current datetime (“now”) in a vue-x store (Vue 2/3) or a Pinia store (Vue 3)
const MILLISECONDS_PER_MINUTES = 1000 * 60;
const state = {
now: (new Date()),
intervalTimer: null,
};
const mutations = {
now(state) {
state.now = new Date();
},
setIntervalTimer(state, callback) {
state.intervalTimer = setInterval(() => {
if (callback) {
callback();
}
}, MILLISECONDS_PER_MINUTES * 3);
},
clearIntervalTimer(state) {
if (state.intervalTimer) {
clearInterval(state.intervalTimer);
state.intervalTimer = null
}
}
};
const actions = {
pollNow({ commit, state }) {
if (!state.intervalTimer) {
commit("setIntervalTimer", () => commit("now"));
}
},
clearPollNow({ commit }) {
commit("clearIntervalTimer");
},
};
const time = {
namespaced: true,
state,
mutations,
actions,
};
export default time;
import { onBeforeMount, onUnmounted, ref } from 'vue'
const REFRESH_INTERVAL_MS = 1000
let timer
let subscribers = 0
/** Current date and time, updated every second. */
const now = ref(new Date())
const poll = () => {
if (!timer) {
timer = setInterval(() => {
now.value = new Date()
}, REFRESH_INTERVAL_MS)
}
}
const stopPoll = () => {
if (timer) {
clearInterval(timer)
timer = null
}
}
/**
* Subscribe to the polling of the current date and time.
* Once subscribed, `now` is periodically updated.
*/
const subscribe = () => {
if (!subscribers++) {
poll()
}
}
/**
* Unsubscribe of the polling of the current date and time.
* Once unsubscribed, `now` may stop to be updated.
*/
const unsubscribe = () => {
subscribers--
if (!subscribers) {
stopPoll()
}
}
/**
* Current date, updated every second.
*
* It start to update automatically on the first component to be mounted, and
* stop updating on the last unmounted one. For non-component usages, use
* `useNowSubscription`.
*/
export const useNow = () => {
onBeforeMount(subscribe)
onUnmounted(unsubscribe)
return { now }
}
/**
* Current date, updated every second.
*
* It requires manual (de)activation using (un)subscribe methods. Suitable in a
* non-component environment (like a store). For components, use `useNow`.
*/
export const useNowSubscription = { subscribe, unsubscribe, now }
@meduzen
Copy link
Author

meduzen commented Mar 9, 2021

What this store module does

It provides action that can start/stop a polling (setInterval) updating the current time (state.now) every 3 minutes.

Approach

I put both the setInterval and clearInterval calls in mutations because they are mutating state.intervalTimer.

setInterval is having a callback mutating another part (state.now), but the decision to mutate another property is driven in an action (pollNow).

I would love feedback on this approach.

@cjbeattie
Copy link

Hi @meduzen, this is really awesome! I was having a bit of trouble implementing something like this myself and your solution helped me out! 😄

@meduzen
Copy link
Author

meduzen commented Jun 13, 2022

Hey, thanks for the feedback @cjbeattie! I forgot I made this gist. 😅

@meduzen
Copy link
Author

meduzen commented Feb 19, 2026

Just added a useNow composable, suitable for Vue 3 composition API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment