diff --git a/docs/3.api/1.composables/use-cookie.md b/docs/3.api/1.composables/use-cookie.md index deea5b7308a7..f36e466f0abb 100644 --- a/docs/3.api/1.composables/use-cookie.md +++ b/docs/3.api/1.composables/use-cookie.md @@ -18,10 +18,6 @@ const cookie = useCookie(name, options) `useCookie` ref will automatically serialize and deserialize cookie value to JSON. :: -::alert{icon=⚠️} -Multiple invocations of `useCookie` with the same name are not synced. [You can utilise `useState()` to sync them as a workaround](https://github.com/nuxt/nuxt/issues/13020#issuecomment-1505548242). -:: - ## Example The example below creates a cookie called `counter`. If the cookie doesn't exist, it is initially set to a random value. Whenever we update the `counter` variable, the cookie will be updated accordingly. diff --git a/packages/nuxt/src/app/composables/cookie.ts b/packages/nuxt/src/app/composables/cookie.ts index 3e3a5dfd10b0..67c001c8bda8 100644 --- a/packages/nuxt/src/app/composables/cookie.ts +++ b/packages/nuxt/src/app/composables/cookie.ts @@ -1,5 +1,5 @@ import type { Ref } from 'vue' -import { ref, watch } from 'vue' +import { getCurrentInstance, nextTick, onUnmounted, ref, watch } from 'vue' import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es' import { parse, serialize } from 'cookie-es' import { deleteCookie, getCookie, setCookie } from 'h3' @@ -34,9 +34,30 @@ export function useCookie (name: string, _opts?: const cookie = ref(cookies[name] as any ?? opts.default?.()) if (process.client) { - const callback = () => { writeClientCookie(name, cookie.value, opts as CookieSerializeOptions) } + const channel = typeof BroadcastChannel === 'undefined' ? null : new BroadcastChannel(`nuxt:cookies:${name}`) + if (getCurrentInstance()) { onUnmounted(() => { channel?.close() }) } + + const callback = () => { + writeClientCookie(name, cookie.value, opts as CookieSerializeOptions) + channel?.postMessage(cookie.value) + } + + let watchPaused = false + + if (channel) { + channel.onmessage = (event) => { + watchPaused = true + cookie.value = event.data + nextTick(() => { watchPaused = false }) + } + } + if (opts.watch) { - watch(cookie, callback, { deep: opts.watch !== 'shallow' }) + watch(cookie, (newVal, oldVal) => { + if (watchPaused || isEqual(newVal, oldVal)) { return } + callback() + }, + { deep: opts.watch !== 'shallow' }) } else { callback() }