packagesreacthooksuseMediaQuery

useMediaQuery

๋ฏธ๋””์–ด ์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ์ถ”์ ํ•˜๋Š” React ํ›…์ž…๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ํ™”๋ฉด ํฌ๊ธฐ, ๋””๋ฐ”์ด์Šค ํŠน์„ฑ, ์‚ฌ์šฉ์ž ํ™˜๊ฒฝ ์„ค์ •์— ๋”ฐ๋ผ ๋ฐ˜์‘ํ˜• UI๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

import { useMediaQuery, media } from '@teamsparta/react';
 
function Example() {
  const isTabletOrLarger = useMediaQuery(media.min(768));
  const isDarkMode = useMediaQuery(media.prefersColorScheme.dark);
 
  return (
    <div className={isDarkMode ? 'dark-theme' : 'light-theme'}>
      {isTabletOrLarger ? <TabletContent /> : <MobileContent />}
    </div>
  );
}

Props

์ด๋ฆ„ํƒ€์ž…์„ค๋ช…๊ธฐ๋ณธ๊ฐ’
queryMediaQueryํ™•์ธํ•  ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ-
defaultValuebooleanSSR ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•  ๊ธฐ๋ณธ๊ฐ’false

Return

boolean - ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ ์ผ์น˜ ์—ฌ๋ถ€ (true ๋˜๋Š” false)

๋ฏธ๋””์–ด ์ฟผ๋ฆฌ ์œ ํ‹ธ๋ฆฌํ‹ฐ (media)

media ๊ฐ์ฒด๋Š” ํƒ€์ž… ์•ˆ์ „ํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค. ์ง์ ‘ ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹  ์ด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํƒ€์ž… ์ฒดํฌ์™€ ์ž๋™ ์™„์„ฑ์„ ํ†ตํ•ด ์•ˆ์ „ํ•˜๊ฒŒ ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ

ํ™”๋ฉด ํฌ๊ธฐ ๊ด€๋ จ
ํ•จ์ˆ˜/์†์„ฑ์„ค๋ช…์ƒ์„ฑ๋˜๋Š” ์ฟผ๋ฆฌ์˜ˆ์‹œ
min(width)์ตœ์†Œ ํ™”๋ฉด ๋„ˆ๋น„(min-width: {width}px)media.min(768)
max(width)์ตœ๋Œ€ ํ™”๋ฉด ๋„ˆ๋น„(max-width: {width}px)media.max(767)
between(minWidth, maxWidth)ํ™”๋ฉด ๋„ˆ๋น„ ๋ฒ”์œ„(min-width: {minWidth}px) and (max-width: {maxWidth}px)media.between(768, 1023)
width(width)์ •ํ™•ํ•œ ํ™”๋ฉด ๋„ˆ๋น„(width: {width}px)media.width(1024)
๋””์Šคํ”Œ๋ ˆ์ด ๋ฐฉํ–ฅ ๋ฐ ๋น„์œจ
ํ•จ์ˆ˜/์†์„ฑ์„ค๋ช…์ƒ์„ฑ๋˜๋Š” ์ฟผ๋ฆฌ์˜ˆ์‹œ
orientation.portrait์„ธ๋กœ ๋ฐฉํ–ฅ(orientation: portrait)media.orientation.portrait
orientation.landscape๊ฐ€๋กœ ๋ฐฉํ–ฅ(orientation: landscape)media.orientation.landscape
aspectRatio.exact(w, h)์ •ํ™•ํ•œ ํ™”๋ฉด ๋น„์œจ(aspect-ratio: {w}/{h})media.aspectRatio.exact(16, 9)
aspectRatio.min(w, h)์ตœ์†Œ ํ™”๋ฉด ๋น„์œจ(min-aspect-ratio: {w}/{h})media.aspectRatio.min(16, 9)
aspectRatio.max(w, h)์ตœ๋Œ€ ํ™”๋ฉด ๋น„์œจ(max-aspect-ratio: {w}/{h})media.aspectRatio.max(16, 9)
๋””๋ฐ”์ด์Šค ์ž…๋ ฅ ๊ด€๋ จ
ํ•จ์ˆ˜/์†์„ฑ์„ค๋ช…์ƒ์„ฑ๋˜๋Š” ์ฟผ๋ฆฌ์˜ˆ์‹œ
pointer.fine๋งˆ์šฐ์Šค ๋“ฑ ์ •๋ฐ€ํ•œ ํฌ์ธํŒ… ์žฅ์น˜(pointer: fine)media.pointer.fine
pointer.coarseํ„ฐ์น˜์Šคํฌ๋ฆฐ ๋“ฑ ๋œ ์ •๋ฐ€ํ•œ ํฌ์ธํŒ… ์žฅ์น˜(pointer: coarse)media.pointer.coarse
pointer.noneํฌ์ธํŒ… ์žฅ์น˜ ์—†์Œ(pointer: none)media.pointer.none
pointer.anyFine์ตœ์†Œ ํ•˜๋‚˜์˜ ์ •๋ฐ€ํ•œ ํฌ์ธํŒ… ์žฅ์น˜(any-pointer: fine)media.pointer.anyFine
pointer.anyCoarse์ตœ์†Œ ํ•˜๋‚˜์˜ ํ„ฐ์น˜์Šคํฌ๋ฆฐ(any-pointer: coarse)media.pointer.anyCoarse
hover.hoverํ˜ธ๋ฒ„ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๋””๋ฐ”์ด์Šค(hover: hover)media.hover.hover
hover.noneํ˜ธ๋ฒ„ ๊ธฐ๋Šฅ์ด ์—†๋Š” ๋””๋ฐ”์ด์Šค(hover: none)media.hover.none
hover.anyHover์ตœ์†Œ ํ•˜๋‚˜์˜ ์ž…๋ ฅ ์žฅ์น˜๊ฐ€ ํ˜ธ๋ฒ„ ์ง€์›(any-hover: hover)media.hover.anyHover
๋””์Šคํ”Œ๋ ˆ์ด ํ’ˆ์งˆ
ํ•จ์ˆ˜/์†์„ฑ์„ค๋ช…์ƒ์„ฑ๋˜๋Š” ์ฟผ๋ฆฌ์˜ˆ์‹œ
resolution.min(dppx)์ตœ์†Œ ํ•ด์ƒ๋„(min-resolution: {dppx}dppx)media.resolution.min(2)
resolution.max(dppx)์ตœ๋Œ€ ํ•ด์ƒ๋„(max-resolution: {dppx}dppx)media.resolution.max(2)
resolution.exact(dppx)์ •ํ™•ํ•œ ํ•ด์ƒ๋„(resolution: {dppx}dppx)media.resolution.exact(2)
resolution.retina๋ ˆํ‹ฐ๋‚˜ ๋””์Šคํ”Œ๋ ˆ์ด(min-resolution: 2dppx)media.resolution.retina
resolution.dpi(dpi)DPI ๊ธฐ๋ฐ˜ ํ•ด์ƒ๋„(resolution: {dpi}dpi)media.resolution.dpi(192)
colorGamut.srgbsRGB ์ƒ‰ ์˜์—ญ(color-gamut: srgb)media.colorGamut.srgb
colorGamut.p3P3 ์ƒ‰ ์˜์—ญ(color-gamut: p3)media.colorGamut.p3
colorGamut.rec2020Rec2020 ์ƒ‰ ์˜์—ญ(color-gamut: rec2020)media.colorGamut.rec2020
์‚ฌ์šฉ์ž ํ™˜๊ฒฝ ์„ค์ •
ํ•จ์ˆ˜/์†์„ฑ์„ค๋ช…์ƒ์„ฑ๋˜๋Š” ์ฟผ๋ฆฌ์˜ˆ์‹œ
prefersColorScheme.dark๋‹คํฌ ๋ชจ๋“œ(prefers-color-scheme: dark)media.prefersColorScheme.dark
prefersColorScheme.light๋ผ์ดํŠธ ๋ชจ๋“œ(prefers-color-scheme: light)media.prefersColorScheme.light
prefersReducedMotion.reduce๋ชจ์…˜ ๊ฐ์†Œ ์„ ํ˜ธ(prefers-reduced-motion: reduce)media.prefersReducedMotion.reduce
prefersReducedMotion.noPreference๋ชจ์…˜ ๊ฐ์†Œ ์„ ํ˜ธํ•˜์ง€ ์•Š์Œ(prefers-reduced-motion: no-preference)media.prefersReducedMotion.noPreference
prefersReducedTransparency.reduceํˆฌ๋ช…๋„ ๊ฐ์†Œ ์„ ํ˜ธ(prefers-reduced-transparency: reduce)media.prefersReducedTransparency.reduce
prefersReducedTransparency.noPreferenceํˆฌ๋ช…๋„ ๊ฐ์†Œ ์„ ํ˜ธํ•˜์ง€ ์•Š์Œ(prefers-reduced-transparency: no-preference)media.prefersReducedTransparency.noPreference
prefersContrast.more๋†’์€ ๋Œ€๋น„ ์„ ํ˜ธ(prefers-contrast: more)media.prefersContrast.more
prefersContrast.less๋‚ฎ์€ ๋Œ€๋น„ ์„ ํ˜ธ(prefers-contrast: less)media.prefersContrast.less
prefersContrast.custom์‚ฌ์šฉ์ž ์ •์˜ ๋Œ€๋น„ ์„ ํ˜ธ(prefers-contrast: custom)media.prefersContrast.custom
prefersContrast.noPreference๋Œ€๋น„ ์„ ํ˜ธ ์—†์Œ(prefers-contrast: no-preference)media.prefersContrast.noPreference
prefersReducedData.reduce๋ฐ์ดํ„ฐ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ ์„ ํ˜ธ(prefers-reduced-data: reduce)media.prefersReducedData.reduce
prefersReducedData.noPreference๋ฐ์ดํ„ฐ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ ์„ ํ˜ธํ•˜์ง€ ์•Š์Œ(prefers-reduced-data: no-preference)media.prefersReducedData.noPreference
ํ™˜๊ฒฝ ๊ด€๋ จ
ํ•จ์ˆ˜/์†์„ฑ์„ค๋ช…์ƒ์„ฑ๋˜๋Š” ์ฟผ๋ฆฌ์˜ˆ์‹œ
invertedColors.inverted์ƒ‰์ƒ ๋ฐ˜์ „ ์ ์šฉ(inverted-colors: inverted)media.invertedColors.inverted
invertedColors.none์ƒ‰์ƒ ๋ฐ˜์ „ ์—†์Œ(inverted-colors: none)media.invertedColors.none
forcedColors.active๊ฐ•์ œ ์ƒ‰์ƒ ํ™œ์„ฑํ™” (๊ณ ๋Œ€๋น„ ๋ชจ๋“œ ๋“ฑ)(forced-colors: active)media.forcedColors.active
forcedColors.none๊ฐ•์ œ ์ƒ‰์ƒ ๋น„ํ™œ์„ฑํ™”(forced-colors: none)media.forcedColors.none
monochrome.anyํ‘๋ฐฑ ํ™”๋ฉด (๋น„ํŠธ ์ˆ˜ ์ƒ๊ด€์—†์Œ)(monochrome)media.monochrome.any
monochrome.bits(bits)ํŠน์ • ๋น„ํŠธ ์ˆ˜์˜ ํ‘๋ฐฑ ํ™”๋ฉด(monochrome: {bits})media.monochrome.bits(8)
๋ณตํ•ฉ ์ฟผ๋ฆฌ
ํ•จ์ˆ˜/์†์„ฑ์„ค๋ช…์ƒ์„ฑ๋˜๋Š” ์ฟผ๋ฆฌ์˜ˆ์‹œ
and(...queries)๋ชจ๋“  ์กฐ๊ฑด ์ถฉ์กฑ (AND){query1} and {query2} and ...media.and(media.prefersColorScheme.dark, media.max(767))
or(...queries)ํ•˜๋‚˜ ์ด์ƒ์˜ ์กฐ๊ฑด ์ถฉ์กฑ (OR){query1}, {query2}, ...media.or(media.orientation.portrait, media.max(767))
not(query)์กฐ๊ฑด ๋ถ€์ • (NOT)not {query}media.not(media.hover.hover)

์œ ์šฉํ•œ ์ฟผ๋ฆฌ ์กฐํ•ฉ ์˜ˆ์ œ

์šฉ๋„์ฟผ๋ฆฌ์„ค๋ช…
๋ฐ˜์‘ํ˜• ๋””์ž์ธmedia.min(768)768px ์ด์ƒ ํ™”๋ฉด (ํƒœ๋ธ”๋ฆฟ/๋ฐ์Šคํฌํƒ‘)
๋ชจ๋ฐ”์ผ ์ „์šฉmedia.max(767)767px ์ดํ•˜ ํ™”๋ฉด (๋ชจ๋ฐ”์ผ)
ํƒœ๋ธ”๋ฆฟ ์ „์šฉmedia.between(768, 1023)768px-1023px ์‚ฌ์ด ํ™”๋ฉด (ํƒœ๋ธ”๋ฆฟ)
ํ„ฐ์น˜ ๋””๋ฐ”์ด์Šคmedia.pointer.coarseํ„ฐ์น˜์Šคํฌ๋ฆฐ ๊ธฐ๊ธฐ
๋งˆ์šฐ์Šค ๊ธฐ๊ธฐmedia.pointer.fine๋งˆ์šฐ์Šค ์‚ฌ์šฉ ๊ธฐ๊ธฐ
๋‹คํฌ ๋ชจ๋“œmedia.prefersColorScheme.dark๋‹คํฌ ๋ชจ๋“œ ์‚ฌ์šฉ์ž
์ ‘๊ทผ์„ฑ ๋ชจ์…˜ ๊ฐ์†Œmedia.prefersReducedMotion.reduce๋ชจ์…˜ ๊ฐ์†Œ ์„ ํ˜ธ ์‚ฌ์šฉ์ž
๋ชจ๋ฐ”์ผ ๋‹คํฌ๋ชจ๋“œmedia.and(media.max(767), media.prefersColorScheme.dark)๋ชจ๋ฐ”์ผ์—์„œ ๋‹คํฌ ๋ชจ๋“œ
ํŠน์ˆ˜ ์ ‘๊ทผ์„ฑmedia.or(media.prefersReducedMotion.reduce, media.prefersHighContrast)๋ชจ์…˜ ๊ฐ์†Œ ๋˜๋Š” ๊ณ ๋Œ€๋น„ ์„ ํ˜ธ

ํ—ฌํผ ํ›…

useMediaQuery ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ํŽธ์˜ ํ›…๋“ค์ž…๋‹ˆ๋‹ค.

ํ™”๋ฉด ํฌ๊ธฐ ๊ด€๋ จ ํ›…
ํ›…๊ธฐ๋Šฅ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ
useMinWidth(width)์ตœ์†Œ ๋„ˆ๋น„ ์ด์ƒ์ธ์ง€ ํ™•์ธ(min-width: {width}px)
useMaxWidth(width)์ตœ๋Œ€ ๋„ˆ๋น„ ์ดํ•˜์ธ์ง€ ํ™•์ธ(max-width: {width}px)
useBetweenWidth(minWidth, maxWidth)๋„ˆ๋น„ ๋ฒ”์œ„ ๋‚ด์ธ์ง€ ํ™•์ธ(min-width: {minWidth}px) and (max-width: {maxWidth}px)
useExactWidth(width)์ •ํ™•ํ•œ ๋„ˆ๋น„์ธ์ง€ ํ™•์ธ(width: {width}px)
๋””๋ฐ”์ด์Šค ์ž…๋ ฅ ๊ด€๋ จ ํ›…
ํ›…๊ธฐ๋Šฅ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ
useIsTouchDevice()ํ„ฐ์น˜ ๋””๋ฐ”์ด์Šค์ธ์ง€ ํ™•์ธ(pointer: coarse)
useIsMouseDevice()๋งˆ์šฐ์Šค ๋””๋ฐ”์ด์Šค์ธ์ง€ ํ™•์ธ(pointer: fine)
useHasHover()ํ˜ธ๋ฒ„ ๊ธฐ๋Šฅ์ด ์žˆ๋Š”์ง€ ํ™•์ธ(hover: hover)
์‚ฌ์šฉ์ž ํ™˜๊ฒฝ ์„ค์ • ๊ด€๋ จ ํ›…
ํ›…๊ธฐ๋Šฅ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ
usePrefersDarkMode()๋‹คํฌ ๋ชจ๋“œ ์„ ํ˜ธ ์—ฌ๋ถ€(prefers-color-scheme: dark)
usePrefersLightMode()๋ผ์ดํŠธ ๋ชจ๋“œ ์„ ํ˜ธ ์—ฌ๋ถ€(prefers-color-scheme: light)
usePrefersReducedMotion()๋ชจ์…˜ ๊ฐ์†Œ ์„ ํ˜ธ ์—ฌ๋ถ€(prefers-reduced-motion: reduce)
usePrefersHighContrast()๊ณ ๋Œ€๋น„ ์„ ํ˜ธ ์—ฌ๋ถ€(prefers-contrast: more)
usePrefersReducedData()๋ฐ์ดํ„ฐ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ ์„ ํ˜ธ ์—ฌ๋ถ€(prefers-reduced-data: reduce)
๋””์Šคํ”Œ๋ ˆ์ด ํŠน์„ฑ ๊ด€๋ จ ํ›…
ํ›…๊ธฐ๋Šฅ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ
useIsPortrait()์„ธ๋กœ ๋ฐฉํ–ฅ ํ™”๋ฉด์ธ์ง€ ํ™•์ธ(orientation: portrait)
useIsLandscape()๊ฐ€๋กœ ๋ฐฉํ–ฅ ํ™”๋ฉด์ธ์ง€ ํ™•์ธ(orientation: landscape)
useIsRetina()๋ ˆํ‹ฐ๋‚˜ ๋””์Šคํ”Œ๋ ˆ์ด์ธ์ง€ ํ™•์ธ(min-resolution: 2dppx)
useSupportsP3ColorGamut()P3 ์ƒ‰ ์˜์—ญ ์ง€์› ์—ฌ๋ถ€(color-gamut: p3)
ํ™˜๊ฒฝ ๊ด€๋ จ ํ›…
ํ›…๊ธฐ๋Šฅ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ
useIsForcedColors()๊ฐ•์ œ ์ƒ‰์ƒ ๋ชจ๋“œ ํ™œ์„ฑํ™” ์—ฌ๋ถ€(forced-colors: active)
useIsInvertedColors()์ƒ‰์ƒ ๋ฐ˜์ „ ํ™œ์„ฑํ™” ์—ฌ๋ถ€(inverted-colors: inverted)
useIsMonochrome()ํ‘๋ฐฑ ํ™”๋ฉด ์—ฌ๋ถ€(monochrome)

์‚ฌ์šฉ ์˜ˆ์ œ

๋ฐ˜์‘ํ˜• ๋ ˆ์ด์•„์›ƒ
function ResponsiveLayout() {
  const isMobile = useMaxWidth(767);
  const isTablet = useBetweenWidth(768, 1023);
  const isDesktop = useMinWidth(1024);
 
  return (
    <div className="layout">
      {isMobile && <MobileLayout />}
      {isTablet && <TabletLayout />}
      {isDesktop && <DesktopLayout />}
    </div>
  );
}
๋‹คํฌ ๋ชจ๋“œ ์ง€์›
function DarkModeSupport() {
  const prefersDarkMode = usePrefersDarkMode();
 
  return (
    <div className={prefersDarkMode ? 'dark-theme' : 'light-theme'}>
      <h1>์•ˆ๋…•ํ•˜์„ธ์š”!</h1>
      <p>ํ˜„์žฌ {prefersDarkMode ? '๋‹คํฌ' : '๋ผ์ดํŠธ'} ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค.</p>
    </div>
  );
}
์ ‘๊ทผ์„ฑ ํ–ฅ์ƒ
function AccessibleButton() {
  const prefersReducedMotion = usePrefersReducedMotion();
 
  return (
    <button
      className={prefersReducedMotion ? 'no-animation' : 'animate'}
      aria-label="ํ™•์ธ"
    >
      ํ™•์ธ
    </button>
  );
}
๋””๋ฐ”์ด์Šค๋ณ„ ์ธํ„ฐํŽ˜์ด์Šค
function DeviceAwareInterface() {
  const isTouchDevice = useIsTouchDevice();
  const hasHover = useHasHover();
 
  return (
    <div>
      {isTouchDevice ? <TouchFriendlyControls /> : <PreciseControls />}
      {hasHover && <HoverEffects />}
    </div>
  );
}
๋ณตํ•ฉ ์กฐ๊ฑด ํ™œ์šฉ
function SmartUI() {
  // ๋ชจ๋ฐ”์ผ์ด๊ฑฐ๋‚˜ ๋ชจ์…˜ ๊ฐ์†Œ ์„ ํ˜ธ ์‹œ ๊ฐ„๋‹จํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‚ฌ์šฉ
  const useSimpleAnimation = useMediaQuery(
    media.or(media.max(767), media.prefersReducedMotion.reduce),
  );
 
  // ํ„ฐ์น˜ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ํฐ ํ™”๋ฉด(ํƒœ๋ธ”๋ฆฟ ๋“ฑ)์—์„œ๋Š” ํŠน๋ณ„ํ•œ UI ์ œ๊ณต
  const isLargeTouch = useMediaQuery(
    media.and(media.min(768), media.pointer.coarse),
  );
 
  return (
    <div>
      <Animations complexity={useSimpleAnimation ? 'simple' : 'rich'} />
      {isLargeTouch && <TouchOptimizedUI />}
    </div>
  );
}

์œ ์˜์‚ฌํ•ญ

SSR ์ง€์›

์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ํ™˜๊ฒฝ์—์„œ๋Š” defaultValue ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

// ๊ธฐ๋ณธ์ ์œผ๋กœ ์„œ๋ฒ„์—์„œ๋Š” ๋ชจ๋ฐ”์ผ๋กœ ์ฒ˜๋ฆฌ (max-width: 767px)
const isMobile = useMediaQuery(media.max(767), true);
ํ˜ธํ™˜์„ฑ

React 18 ์ด์ƒ์—์„œ๋Š” useSyncExternalStore๋ฅผ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

18๋ฒ„์ „ ๋ฏธ๋งŒ์—์„œ๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.