Skip to content

Commit

Permalink
fix(useMediaQuery): only add/remove event listeners on query change (#…
Browse files Browse the repository at this point in the history
…3236)

Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
Ingramz and antfu committed Jul 30, 2023
1 parent 5309c26 commit f39691f
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -11,7 +11,7 @@
"build:redirects": "esno scripts/redirects.ts",
"build:rollup": "NODE_OPTIONS=\"--max-old-space-size=6144\" rollup -c",
"build:types": "tsc --emitDeclarationOnly && nr types:fix",
"clean": "rimraf dist types \"packages/*/dist\"",
"clean": "rimraf --glob dist types \"packages/*/dist\"",
"dev": "nr update && nr docs",
"docs": "vue-demi-switch 3 && vitepress dev packages --open",
"docs:build": "nr update:full && vitepress build packages && nr build:redirects && esno scripts/post-docs.ts",
Expand Down
35 changes: 19 additions & 16 deletions packages/core/useMediaQuery/index.ts
Expand Up @@ -2,7 +2,7 @@

import { ref, watchEffect } from 'vue-demi'
import type { MaybeRefOrGetter } from '@vueuse/shared'
import { toRef, tryOnScopeDispose } from '@vueuse/shared'
import { toValue, tryOnScopeDispose } from '@vueuse/shared'
import type { ConfigurableWindow } from '../_configurable'
import { defaultWindow } from '../_configurable'
import { useSupported } from '../useSupported'
Expand All @@ -21,39 +21,42 @@ export function useMediaQuery(query: MaybeRefOrGetter<string>, options: Configur
let mediaQuery: MediaQueryList | undefined
const matches = ref(false)

const handler = (event: MediaQueryListEvent) => {
matches.value = event.matches
}

const cleanup = () => {
if (!mediaQuery)
return
if ('removeEventListener' in mediaQuery)
// eslint-disable-next-line @typescript-eslint/no-use-before-define
mediaQuery.removeEventListener('change', update)
mediaQuery.removeEventListener('change', handler)
else
// @ts-expect-error deprecated API
// eslint-disable-next-line @typescript-eslint/no-use-before-define
mediaQuery.removeListener(update)
mediaQuery.removeListener(handler)
}

const update = () => {
const stopWatch = watchEffect(() => {
if (!isSupported.value)
return

cleanup()

mediaQuery = window!.matchMedia(toRef(query).value)
matches.value = !!mediaQuery?.matches

if (!mediaQuery)
return
mediaQuery = window!.matchMedia(toValue(query))

if ('addEventListener' in mediaQuery)
mediaQuery.addEventListener('change', update)
mediaQuery.addEventListener('change', handler)
else
// @ts-expect-error deprecated API
mediaQuery.addListener(update)
}
watchEffect(update)
mediaQuery.addListener(handler)

tryOnScopeDispose(() => cleanup())
matches.value = mediaQuery.matches
})

tryOnScopeDispose(() => {
stopWatch()
cleanup()
mediaQuery = undefined
})

return matches
}
16 changes: 13 additions & 3 deletions packages/core/useWindowSize/index.test.ts
Expand Up @@ -4,10 +4,20 @@ import { useWindowSize } from '.'

describe('useWindowSize', () => {
const addEventListenerSpy = vi.spyOn(window, 'addEventListener')
const matchMediaSpy = vi.spyOn(window, 'matchMedia')
const matchMediaSpy = vi.spyOn(window, 'matchMedia').mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: vi.fn(),
removeListener: vi.fn(),
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
dispatchEvent: vi.fn(),
}))

beforeEach(() => {
addEventListenerSpy.mockReset()
matchMediaSpy.mockReset()
addEventListenerSpy.mockClear()
matchMediaSpy.mockClear()
})

afterAll(() => {
Expand Down

0 comments on commit f39691f

Please sign in to comment.