Skip to content

Commit

Permalink
fix(useRouteQuery,useRouteParams): prevent reset on other scope dispo…
Browse files Browse the repository at this point in the history
…se (#3418)

Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
s-montigny-desautels and antfu committed Nov 9, 2023
1 parent 082462d commit 771e7ff
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 30 deletions.
31 changes: 31 additions & 0 deletions packages/router/useRouteParams/index.test.ts
Expand Up @@ -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<any> = ref(null)
await scopeA.run(async () => {
page1 = useRouteParams('page', defaultPage, { route, router })
})

let page2: Ref<any> = 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
Expand Down
36 changes: 21 additions & 15 deletions packages/router/useRouteParams/index.ts
Expand Up @@ -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<Router, Map<string, any>>()

export function useRouteParams(
name: string
Expand Down Expand Up @@ -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<string, any> = _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<any>((track, trigger) => {
Expand All @@ -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,
Expand All @@ -86,7 +92,7 @@ export function useRouteParams<
watch(
() => route.params[name],
(v) => {
_params.set(name, v)
param = v

_trigger()
},
Expand Down
32 changes: 31 additions & 1 deletion packages/router/useRouteQuery/index.test.ts
Expand Up @@ -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<any> = ref(null)
await scopeA.run(async () => {
page1 = useRouteQuery('page', defaultPage, { route, router })
})

let page2: Ref<any> = 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
Expand All @@ -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,
})
Expand Down
34 changes: 20 additions & 14 deletions 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<Router, Map<string, any>>()

export function useRouteQuery(
name: string
Expand Down Expand Up @@ -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<string, any> = _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<any>((track, trigger) => {
Expand All @@ -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,
})
})
Expand All @@ -83,7 +89,7 @@ export function useRouteQuery<
watch(
() => route.query[name],
(v) => {
_query.set(name, v)
query = v

_trigger()
},
Expand Down

0 comments on commit 771e7ff

Please sign in to comment.