useMediaQuery

useMediaQuery — это React-хук из библиотеки Chakra UI, предназначенный для отслеживания медиазапросов CSS непосредственно внутри компонентов. Он позволяет реагировать на изменения размеров экрана, ориентации устройства, цветовой схемы и других характеристик среды отображения.

Хук служит программным дополнением к адаптивным возможностям CSS и используется в ситуациях, когда поведение интерфейса должно изменяться не только визуально, но и логически.


Импорт

Хук импортируется напрямую из пакета Chakra UI:

import { useMediaQuery } from "@chakra-ui/react"

Базовый синтаксис

Основная форма использования:

const [isLargerThan768] = useMediaQuery("(min-width: 768px)")

Аргументом передаётся строка с медиазапросом CSS.

Возвращаемое значение — массив булевых значений, где каждое значение соответствует одному медиазапросу.

Пример использования:

function Example() {
  const [isDesktop] = useMediaQuery("(min-width: 1024px)")

  return (
    <div>
      {isDesktop ? "Desktop view" : "Mobile view"}
    </div>
  )
}

При изменении ширины экрана React автоматически инициирует повторный рендер компонента.


Возвращаемое значение

useMediaQuery всегда возвращает массив, даже если передан только один запрос.

const [matches] = useMediaQuery("(min-width: 768px)")

Тип возвращаемого значения:

boolean[]

Если передаётся несколько медиазапросов, каждый из них возвращает собственное булево значение.


Несколько медиазапросов

Хук поддерживает одновременное отслеживание нескольких условий.

const [isTablet, isDesktop] = useMediaQuery([
  "(min-width: 768px)",
  "(min-width: 1024px)"
])

Использование:

function Layout() {
  const [isTablet, isDesktop] = useMediaQuery([
    "(min-width: 768px)",
    "(min-width: 1200px)"
  ])

  if (isDesktop) {
    return <DesktopLayout />
  }

  if (isTablet) {
    return <TabletLayout />
  }

  return <MobileLayout />
}

Такой подход удобен для программного управления адаптивными макетами.


Объект настроек

Вторым аргументом можно передать объект конфигурации.

useMediaQuery(query, options)

Структура параметров:

{
  ssr?: boolean
  fallback?: boolean
}

Параметр ssr

При использовании серверного рендеринга (SSR) медиазапросы не могут быть вычислены на сервере, поскольку отсутствует объект window.

Поэтому Chakra UI позволяет указать поведение через параметр ssr.

const [isDesktop] = useMediaQuery("(min-width: 1024px)", {
  ssr: true
})

Если ssr: true, хук будет использовать значение fallback до момента гидратации на клиенте.


Параметр fallback

fallback задаёт значение, которое будет возвращено на сервере.

const [isDesktop] = useMediaQuery("(min-width: 1024px)", {
  ssr: true,
  fallback: false
})

На сервере значение будет равно false, а после загрузки страницы на клиенте произойдёт пересчёт.

Это важно для предотвращения несоответствия HTML между сервером и клиентом.


Проверка ширины экрана

Один из самых распространённых сценариев — проверка ширины экрана.

const [isMobile] = useMediaQuery("(max-width: 768px)")

Использование:

function Menu() {
  const [isMobile] = useMediaQuery("(max-width: 768px)")

  return (
    <>
      {isMobile ? <MobileMenu /> : <DesktopMenu />}
    </>
  )
}

Определение ориентации устройства

Медиазапросы позволяют отслеживать ориентацию.

const [isLandscape] = useMediaQuery("(orientation: landscape)")

Пример:

function OrientationExample() {
  const [isLandscape] = useMediaQuery("(orientation: landscape)")

  return (
    <div>
      {isLandscape ? "Landscape mode" : "Portrait mode"}
    </div>
  )
}

Отслеживание цветовой схемы

Можно определять предпочтения пользователя по цветовой теме.

const [prefersDarkMode] = useMediaQuery("(prefers-color-scheme: dark)")

Пример:

function ThemeIndicator() {
  const [prefersDarkMode] = useMediaQuery("(prefers-color-scheme: dark)")

  return (
    <div>
      {prefersDarkMode ? "Dark mode preferred" : "Light mode preferred"}
    </div>
  )
}

Проверка поддержки hover

Некоторые устройства не поддерживают hover-взаимодействие (например, сенсорные экраны).

const [hasHover] = useMediaQuery("(hover: hover)")

Пример:

function HoverExample() {
  const [hasHover] = useMediaQuery("(hover: hover)")

  return (
    <div>
      {hasHover ? "Mouse hover available" : "Touch device"}
    </div>
  )
}

Работа с breakpoints Chakra UI

Chakra UI уже имеет систему breakpoints:

sm: 30em
md: 48em
lg: 62em
xl: 80em
2xl: 96em

Эти значения можно использовать внутри медиазапросов.

const [isLarge] = useMediaQuery("(min-width: 62em)")

Однако в большинстве случаев для адаптивности Chakra UI предлагает responsive props, поэтому useMediaQuery применяется тогда, когда требуется логическая реакция в JavaScript, а не только стили.


Условная загрузка компонентов

Хук позволяет избегать загрузки тяжёлых компонентов на маленьких устройствах.

function Dashboard() {
  const [isDesktop] = useMediaQuery("(min-width: 1024px)")

  return (
    <>
      <MainContent />
      {isDesktop && <LargeAnalyticsPanel />}
    </>
  )
}

Это уменьшает нагрузку на мобильные устройства.


Переключение логики интерфейса

Иногда поведение интерфейса должно различаться между мобильными и десктопными версиями.

function Sidebar() {
  const [isDesktop] = useMediaQuery("(min-width: 1024px)")

  const mode = isDesktop ? "persistent" : "drawer"

  return <Navigation mode={mode} />
}

В этом случае изменяется механика интерфейса, а не только его внешний вид.


Использование внутри кастомных хуков

useMediaQuery часто применяется при создании собственных адаптивных хуков.

function useDeviceType() {
  const [isTablet, isDesktop] = useMediaQuery([
    "(min-width: 768px)",
    "(min-width: 1200px)"
  ])

  if (isDesktop) return "desktop"
  if (isTablet) return "tablet"
  return "mobile"
}

Применение:

function App() {
  const device = useDeviceType()

  return <div>Device: {device}</div>
}

Отличие от responsive props

Chakra UI предоставляет встроенную систему адаптивных свойств.

Пример:

<Box
  fontSize={{ base: "14px", md: "18px", lg: "22px" }}
>

Такие свойства подходят для визуальных изменений.

useMediaQuery используется в других случаях:

  • изменение логики компонентов
  • условная загрузка компонентов
  • управление состояниями
  • переключение алгоритмов интерфейса

Внутренний механизм работы

Хук использует API браузера:

window.matchMedia()

Алгоритм работы:

  1. создаётся объект MediaQueryList
  2. проверяется соответствие медиазапросу
  3. добавляется слушатель изменений
  4. при изменении условия обновляется состояние React

Схематично:

const mediaQuery = window.matchMedia(query)

setState(mediaQuery.matches)

mediaQuery.addEventListener("change", listener)

Chakra UI инкапсулирует этот механизм внутри React-хука.


Оптимизация производительности

Каждый вызов useMediaQuery создаёт собственный listener.

При большом количестве компонентов рекомендуется:

  • выносить медиазапросы в кастомные хуки
  • избегать дублирования запросов
  • использовать breakpoints Chakra UI

Пример оптимизации:

function useIsDesktop() {
  const [isDesktop] = useMediaQuery("(min-width: 1024px)")
  return isDesktop
}

Частые ошибки

Неправильная деструктуризация

Хук возвращает массив, а не значение.

Неверно:

const isDesktop = useMediaQuery("(min-width: 1024px)")

Правильно:

const [isDesktop] = useMediaQuery("(min-width: 1024px)")

Игнорирование SSR

При использовании Next.js может возникнуть предупреждение о несоответствии HTML.

Решение:

useMediaQuery("(min-width: 1024px)", {
  ssr: true,
  fallback: false
})

Дублирование медиазапросов

Неправильно:

const [isDesktop] = useMediaQuery("(min-width: 1024px)")
const [isLarge] = useMediaQuery("(min-width: 1024px)")

Лучше использовать единый хук.


Когда применять useMediaQuery

Подходящие сценарии:

  • переключение логики интерфейса
  • условная загрузка компонентов
  • адаптивные алгоритмы интерфейса
  • реакция на системные настройки пользователя
  • проверка возможностей устройства

Хук занимает важное место в архитектуре адаптивных React-приложений, позволяя переносить медиазапросы из CSS в уровень программной логики интерфейса.