diff --git a/packages/router/useRouteParams/index.test.ts b/packages/router/useRouteParams/index.test.ts index 273d431f2f9..e3407d3366f 100644 --- a/packages/router/useRouteParams/index.test.ts +++ b/packages/router/useRouteParams/index.test.ts @@ -144,6 +144,37 @@ describe('useRouteParams', () => { expect(lang.value).toBeNull() }) + it('should not reset params to default if is disposed from other scope', async () => { + let route = getRoute() + + const router = { replace: (r: any) => route = r } as any + + const scopeA = effectScope() + const scopeB = effectScope() + + route.params.page = 2 + + const defaultPage = 'DEFAULT_PAGE' + let page1: Ref = ref(null) + await scopeA.run(async () => { + page1 = useRouteParams('page', defaultPage, { route, router }) + }) + + let page2: Ref = ref(null) + await scopeB.run(async () => { + page2 = useRouteParams('page', defaultPage, { route, router }) + }) + + expect(page1.value).toBe(2) + expect(page2.value).toBe(2) + + scopeA.stop() + await nextTick() + + expect(page1.value).toBe(defaultPage) + expect(page2.value).toBe(2) + }) + it('should change the value when the route changes', () => { let route = getRoute() const router = { replace: (r: any) => route = r } as any diff --git a/packages/router/useRouteParams/index.ts b/packages/router/useRouteParams/index.ts index e17f38f1d3d..b968baaac67 100644 --- a/packages/router/useRouteParams/index.ts +++ b/packages/router/useRouteParams/index.ts @@ -3,10 +3,10 @@ import { useRoute, useRouter } from 'vue-router' import { toValue, tryOnScopeDispose } from '@vueuse/shared' import type { Ref } from 'vue-demi' import type { MaybeRefOrGetter } from '@vueuse/shared' -import type { LocationAsRelativeRaw, RouteParamValueRaw } from 'vue-router' +import type { LocationAsRelativeRaw, RouteParamValueRaw, Router } from 'vue-router' import type { ReactiveRouteOptionsWithTransform } from '../_types' -const _cache = new WeakMap() +const _queue = new WeakMap>() export function useRouteParams( name: string @@ -36,17 +36,17 @@ export function useRouteParams< transform = value => value as any as K, } = options - if (!_cache.has(route)) - _cache.set(route, new Map()) + if (!_queue.has(router)) + _queue.set(router, new Map()) - const _params: Map = _cache.get(route) + const _paramsQueue = _queue.get(router)! + + let param = route.params[name] as any tryOnScopeDispose(() => { - _params.delete(name) + param = undefined }) - _params.set(name, route.params[name]) - let _trigger: () => void const proxy = customRef((track, trigger) => { @@ -56,24 +56,30 @@ export function useRouteParams< get() { track() - const data = _params.get(name) - - return transform(data !== undefined ? data : toValue(defaultValue)) + return transform(param !== undefined ? param : toValue(defaultValue)) }, set(v) { - if (_params.get(name) === v) + if (param === v) return - _params.set(name, v) + param = v + _paramsQueue.set(name, v) trigger() nextTick(() => { + if (_paramsQueue.size === 0) + return + + const newParams = Object.fromEntries(_paramsQueue.entries()) + _paramsQueue.clear() + const { params, query, hash } = route + router[toValue(mode)]({ params: { ...params, - ...Object.fromEntries(_params.entries()), + ...newParams, }, query, hash, @@ -86,7 +92,7 @@ export function useRouteParams< watch( () => route.params[name], (v) => { - _params.set(name, v) + param = v _trigger() }, diff --git a/packages/router/useRouteQuery/index.test.ts b/packages/router/useRouteQuery/index.test.ts index c18edda23ad..34e2e18b308 100644 --- a/packages/router/useRouteQuery/index.test.ts +++ b/packages/router/useRouteQuery/index.test.ts @@ -142,6 +142,36 @@ describe('useRouteQuery', () => { expect(lang.value).toBeNull() }) + it('should not reset params to default params is disposed from other scope', async () => { + let route = getRoute() + + const router = { replace: (r: any) => route = r } as any + const scopeA = effectScope() + const scopeB = effectScope() + + route.query.page = 2 + + const defaultPage = 'DEFAULT_PAGE' + let page1: Ref = ref(null) + await scopeA.run(async () => { + page1 = useRouteQuery('page', defaultPage, { route, router }) + }) + + let page2: Ref = ref(null) + await scopeB.run(async () => { + page2 = useRouteQuery('page', defaultPage, { route, router }) + }) + + expect(page1.value).toBe(2) + expect(page2.value).toBe(2) + + scopeA.stop() + await nextTick() + + expect(page1.value).toBe(defaultPage) + expect(page2.value).toBe(2) + }) + it('should change the value when the route changes', () => { let route = getRoute() const router = { replace: (r: any) => route = r } as any @@ -155,7 +185,7 @@ describe('useRouteQuery', () => { expect(page.value).toBe('2') }) - it ('should differentiate null and undefined', () => { + it('should differentiate null and undefined', () => { let route = getRoute({ page: 1, }) diff --git a/packages/router/useRouteQuery/index.ts b/packages/router/useRouteQuery/index.ts index 7f20a94705c..9d33947af15 100644 --- a/packages/router/useRouteQuery/index.ts +++ b/packages/router/useRouteQuery/index.ts @@ -1,11 +1,12 @@ import { customRef, nextTick, watch } from 'vue-demi' import { toValue, tryOnScopeDispose } from '@vueuse/shared' import { useRoute, useRouter } from 'vue-router' +import type { Router } from 'vue-router' import type { Ref } from 'vue-demi' import type { MaybeRefOrGetter } from '@vueuse/shared' import type { ReactiveRouteOptionsWithTransform, RouteQueryValueRaw } from '../_types' -const _cache = new WeakMap() +const _queue = new WeakMap>() export function useRouteQuery( name: string @@ -35,17 +36,17 @@ export function useRouteQuery< transform = value => value as any as K, } = options - if (!_cache.has(route)) - _cache.set(route, new Map()) + if (!_queue.has(router)) + _queue.set(router, new Map()) - const _query: Map = _cache.get(route) + const _queriesQueue = _queue.get(router)! + + let query = route.query[name] as any tryOnScopeDispose(() => { - _query.delete(name) + query = undefined }) - _query.set(name, route.query[name]) - let _trigger: () => void const proxy = customRef((track, trigger) => { @@ -55,24 +56,29 @@ export function useRouteQuery< get() { track() - const data = _query.get(name) - - return transform(data !== undefined ? data : toValue(defaultValue)) + return transform(query !== undefined ? query : toValue(defaultValue)) }, set(v) { - if (_query.get(name) === v) + if (query === v) return - _query.set(name, v) + query = v + _queriesQueue.set(name, v) trigger() nextTick(() => { + if (_queriesQueue.size === 0) + return + + const newQueries = Object.fromEntries(_queriesQueue.entries()) + _queriesQueue.clear() + const { params, query, hash } = route router[toValue(mode)]({ params, - query: { ...query, ...Object.fromEntries(_query.entries()) }, + query: { ...query, ...newQueries }, hash, }) }) @@ -83,7 +89,7 @@ export function useRouteQuery< watch( () => route.query[name], (v) => { - _query.set(name, v) + query = v _trigger() },