mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
fix(nuxt): watch custom cookieRef
values deeply (#26151)
This commit is contained in:
parent
5c284ffda8
commit
6407cea620
@ -55,7 +55,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
||||
|
||||
// use a custom ref to expire the cookie on client side otherwise use basic ref
|
||||
const cookie = import.meta.client && delay && !hasExpired
|
||||
? cookieRef<T | undefined>(cookieValue, delay)
|
||||
? cookieRef<T | undefined>(cookieValue, delay, opts.watch && opts.watch !== 'shallow')
|
||||
: ref<T | undefined>(cookieValue)
|
||||
|
||||
if (import.meta.dev && hasExpired) {
|
||||
@ -123,9 +123,9 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
||||
return cookie as CookieRef<T>
|
||||
}
|
||||
/** @since 3.10.0 */
|
||||
export function refreshCookie(name: string) {
|
||||
export function refreshCookie (name: string) {
|
||||
if (store || typeof BroadcastChannel === 'undefined') return
|
||||
|
||||
|
||||
new BroadcastChannel(`nuxt:cookies:${name}`)?.postMessage({ refresh: true })
|
||||
}
|
||||
|
||||
@ -174,14 +174,21 @@ function writeServerCookie (event: H3Event, name: string, value: any, opts: Cook
|
||||
const MAX_TIMEOUT_DELAY = 2_147_483_647
|
||||
|
||||
// custom ref that will update the value to undefined if the cookie expires
|
||||
function cookieRef<T> (value: T | undefined, delay: number) {
|
||||
function cookieRef<T> (value: T | undefined, delay: number, shouldWatch: boolean) {
|
||||
let timeout: NodeJS.Timeout
|
||||
let unsubscribe: (() => void) | undefined
|
||||
let elapsed = 0
|
||||
const internalRef = shouldWatch ? ref(value) : { value }
|
||||
if (getCurrentScope()) {
|
||||
onScopeDispose(() => { clearTimeout(timeout) })
|
||||
onScopeDispose(() => {
|
||||
unsubscribe?.()
|
||||
clearTimeout(timeout)
|
||||
})
|
||||
}
|
||||
|
||||
return customRef((track, trigger) => {
|
||||
if (shouldWatch) { unsubscribe = watch(internalRef, trigger) }
|
||||
|
||||
function createExpirationTimeout () {
|
||||
clearTimeout(timeout)
|
||||
const timeRemaining = delay - elapsed
|
||||
@ -190,7 +197,7 @@ function cookieRef<T> (value: T | undefined, delay: number) {
|
||||
elapsed += timeoutLength
|
||||
if (elapsed < delay) { return createExpirationTimeout() }
|
||||
|
||||
value = undefined
|
||||
internalRef.value = undefined
|
||||
trigger()
|
||||
}, timeoutLength)
|
||||
}
|
||||
@ -198,12 +205,12 @@ function cookieRef<T> (value: T | undefined, delay: number) {
|
||||
return {
|
||||
get () {
|
||||
track()
|
||||
return value
|
||||
return internalRef.value
|
||||
},
|
||||
set (newValue) {
|
||||
createExpirationTimeout()
|
||||
|
||||
value = newValue
|
||||
internalRef.value = newValue
|
||||
trigger()
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,7 @@ describe('composables', () => {
|
||||
'useRequestFetch',
|
||||
'isPrerendered',
|
||||
'useRequestHeaders',
|
||||
'useCookie',
|
||||
'clearNuxtState',
|
||||
'useState',
|
||||
'useRequestURL',
|
||||
@ -121,7 +122,6 @@ describe('composables', () => {
|
||||
'preloadRouteComponents',
|
||||
'reloadNuxtApp',
|
||||
'refreshCookie',
|
||||
'useCookie',
|
||||
'useFetch',
|
||||
'useHead',
|
||||
'useLazyFetch',
|
||||
@ -628,6 +628,33 @@ describe('defineNuxtComponent', () => {
|
||||
it.todo('should support Options API head')
|
||||
})
|
||||
|
||||
describe('useCookie', () => {
|
||||
it('should watch custom cookie refs', () => {
|
||||
const user = useCookie('userInfo', {
|
||||
default: () => ({ score: -1 }),
|
||||
maxAge: 60 * 60,
|
||||
})
|
||||
const computedVal = computed(() => user.value.score)
|
||||
expect(computedVal.value).toBe(-1)
|
||||
user.value.score++
|
||||
expect(computedVal.value).toBe(0)
|
||||
})
|
||||
|
||||
it('should not watch custom cookie refs when shallow', () => {
|
||||
for (const value of ['shallow', false] as const) {
|
||||
const user = useCookie('shallowUserInfo', {
|
||||
default: () => ({ score: -1 }),
|
||||
maxAge: 60 * 60,
|
||||
watch: value
|
||||
})
|
||||
const computedVal = computed(() => user.value.score)
|
||||
expect(computedVal.value).toBe(-1)
|
||||
user.value.score++
|
||||
expect(computedVal.value).toBe(-1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('callOnce', () => {
|
||||
it('should only call composable once', async () => {
|
||||
const fn = vi.fn()
|
||||
@ -643,7 +670,7 @@ describe('callOnce', () => {
|
||||
await Promise.all([execute(), execute(), execute()])
|
||||
expect(fn).toHaveBeenCalledTimes(1)
|
||||
|
||||
const fnSync = vi.fn().mockImplementation(() => { })
|
||||
const fnSync = vi.fn().mockImplementation(() => {})
|
||||
const executeSync = () => callOnce(fnSync)
|
||||
await Promise.all([executeSync(), executeSync(), executeSync()])
|
||||
expect(fnSync).toHaveBeenCalledTimes(1)
|
||||
|
Loading…
Reference in New Issue
Block a user