Skip to content

Commit

Permalink
🐛 Fix hydration issues in both useScreen and useMediaQuery (Fixes #394,…
Browse files Browse the repository at this point in the history
… thanks to @bryantcodesart) (#445)
  • Loading branch information
juliencrn authored Jan 27, 2024
1 parent 5a18619 commit fc8a30e
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-spiders-explode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"usehooks-ts": minor
---

Fix hydration issues in both useScreen and useMediaQuery (Fixes #394, thanks to @bryantcodesart)
35 changes: 20 additions & 15 deletions packages/usehooks-ts/src/useMediaQuery/useMediaQuery.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
import { useEffect, useState } from 'react'
import { useState } from 'react'

const getMatches = (query: string): boolean => {
// Prevents SSR issues
if (typeof window !== 'undefined') {
return window.matchMedia(query).matches
}
return false
}
import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect'

/**
* Custom hook for tracking the state of a media query.
* @param {string} query - The media query to track.
* @param {?boolean} [defaultValue] - The default value to return if the hook is being run on the server (default is `false`).
* @returns {boolean} The current state of the media query (true if the query matches, false otherwise).
* @see [Documentation](https://usehooks-ts.com/react-hook/use-media-query)
* @see [MDN Match Media](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
* @example
* const isSmallScreen = useMediaQuery('(max-width: 600px)');
* // Use `isSmallScreen` to conditionally apply styles or logic based on the screen size.
*/
export function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState<boolean>(getMatches(query))

useEffect(() => {
/** Handles the change event of the media query. */
function handleChange() {
setMatches(getMatches(query))
export function useMediaQuery(
query: string,
defaultValue: boolean = false,
): boolean {
const [matches, setMatches] = useState<boolean>(defaultValue)

const getMatches = (query: string): boolean => {
if (typeof window !== 'undefined') {
return window.matchMedia(query).matches
}
return defaultValue
}

/** Handles the change event of the media query. */
function handleChange() {
setMatches(getMatches(query))
}

useIsomorphicLayoutEffect(() => {
const matchMedia = window.matchMedia(query)

// Triggered at the first client-side load and if query changes
Expand Down
8 changes: 4 additions & 4 deletions packages/usehooks-ts/src/useScreen/useScreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect'
* const currentScreen = useScreen();
* // Access properties of the current screen, such as width and height.
*/
export function useScreen() {
export function useScreen(): Screen | undefined {
const getScreen = () => {
if (typeof window !== 'undefined' && window.screen) {
if (typeof window !== 'undefined') {
return window.screen
}
return undefined
}

const [screen, setScreen] = useState<Screen | undefined>(getScreen())
const [screen, setScreen] = useState<Screen | undefined>(undefined)

/** Handles the resize event of the window. */
function handleSize() {
setScreen(getScreen())
}

// TODO: Prefer incoming useResizeObserver hook
useEventListener('resize', handleSize)

// Set size at the first client-side load
useIsomorphicLayoutEffect(() => {
handleSize()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

return screen
Expand Down

0 comments on commit fc8a30e

Please sign in to comment.