Pular para o conteúdo

useMediaQuery

Este é um hook de CSS media query para React. Ele ouve correspondências para uma consulta de mídia no CSS. Permite a renderização de componentes com base no fato de a consulta corresponder ou não.

Algumas das principais características:

  • ⚛️ Tem uma API React idiomática.
  • 🚀 Com desempenho, ele observa o documento para detectar quando suas consultas de mídia mudam, em vez de pesquisar os valores periodicamente.
  • 📦 1 kB gzipped.
  • 🤖 Ele suporta a renderização do lado do servidor.

Consulta de mídia simples

Você deve fornecer uma consulta de mídia ao primeiro argumento do hook. The media query string can be any valid CSS media query, e.g. '(prefers-color-scheme: dark)'.

(min-width:600px) matches: false
import React from 'react';
import useMediaQuery from '@material-ui/core/useMediaQuery';

export default function SimpleMediaQuery() {
  const matches = useMediaQuery('(min-width:600px)');

  return <span>{`(min-width:600px) matches: ${matches}`}</span>;
}

⚠️ You can't use 'print' per browsers limitation, e.g. Firefox.

Usando helpers de ponto de quebra do Material-UI

Você pode usar os helpers de ponto de quebra do Material-UI da seguinte maneira:

import { useTheme } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';

function MyComponent() {
  const theme = useTheme();
  const matches = useMediaQuery(theme.breakpoints.up('sm'));

  return <span>{`theme.breakpoints.up('sm') matches: ${matches}`}</span>;
}
theme.breakpoints.up('sm') matches: false

Como alternativa, você pode usar uma função de retorno de chamada, aceitando o tema como um primeiro argumento:

import useMediaQuery from '@material-ui/core/useMediaQuery';

function MyComponent() {
  const matches = useMediaQuery(theme => theme.breakpoints.up('sm'));

  return <span>{`theme.breakpoints.up('sm') matches: ${matches}`}</span>;
}

⚠️ Não há nenhum suporte de tema padrão, você precisa injetá-lo em um provedor de temas.

Usando a sintaxe JavaScript

Você pode usar json2mq para gerar uma string de consulta de mídia a partir de um objeto JavaScript.

{ minWidth: 600 } matches: false
import React from 'react';
import json2mq from 'json2mq';
import useMediaQuery from '@material-ui/core/useMediaQuery';

export default function JavaScriptMedia() {
  const matches = useMediaQuery(
    json2mq({
      minWidth: 600,
    }),
  );

  return <span>{`{ minWidth: 600 } matches: ${matches}`}</span>;
}

Testando

Você precisa de uma implementação de matchMedia em seu ambiente de teste.

Por exemplo, jsdom não suporta ainda. Você deve usar um polyfill para isso. É recomendável usar css-mediaquery para emular.

import mediaQuery from 'css-mediaquery';

function createMatchMedia(width) {
  return query => ({
    matches: mediaQuery.match(query, { width }),
    addListener: () => {},
    removeListener: () => {},
  });
}

describe('MeusTestes', () => {
  beforeAll(() => {
    window.matchMedia = createMatchMedia(window.innerWidth);
  });
});

Renderização no servidor (Server-Side Rendering)

⚠️ Renderização do lado servidor e consultas de mídia do lado cliente são fundamentalmente conflitantes. Esteja ciente da escolha. O suporte só pode ser parcial.

Tente confiar em consultas de mídia CSS do lado do cliente primeiro. Por exemplo, você poderia usar:

Se nenhuma das alternativas acima for uma opção, você poderá continuar lendo esta seção da documentação.

Primeiro, você precisa adivinhar as características da solicitação do cliente, no servidor. Você tem a opção entre usar:

  • User agent. Analise a string do user agent do cliente para extrair informações. É recomendável usar ua-parser-js para analisar o user agent.
  • Client hints. Leia as dicas que o cliente está enviando para o servidor. Esteja ciente de que esse recurso não é suportado em qualquer lugar.

Por fim, você precisa fornecer uma implementação de matchMedia para o useMediaQuery com as características adivinhadas anteriormente. É recomendável usar css-mediaquery para emular o matchMedia.

For instance on the server-side:

import ReactDOMServer from 'react-dom/server';
import parser from 'ua-parser-js';
import mediaQuery from 'css-mediaquery';
import { ThemeProvider } from '@material-ui/core/styles';

function handleRender(req, res) {
  const deviceType = parser(req.headers['user-agent']).device.type || 'desktop';
  const ssrMatchMedia = query => ({
    matches: mediaQuery.match(query, {
      // The estimated CSS width of the browser.
      width: deviceType === 'mobile' ? '0px' : '1024px',
    }),
  });

  const html = ReactDOMServer.renderToString(
    <ThemeProvider
      theme={{
        props: {
          // Change the default options of useMediaQuery
          MuiUseMediaQuery: { ssrMatchMedia },
        },
      }}
    >
      <App />
    </ThemeProvider>,
  );

  // …
}
(min-width:600px) matches: true

Make sure you provide the same custom match media implementation to the client-side to guarantee a hydration match.

Migrando de withWidth()

O componente de ordem superior withWidth() injeta a largura da tela da página. Você pode reproduzir o mesmo comportamento com o hook useWidth:

width: xs
<ThemeProvider theme={theme}>
  <MyComponent />
</ThemeProvider>

API

useMediaQuery(query, [options]) => matches

Argumentos

  1. query (String | Function): Uma string representando a consulta de mídia a ser manipulada ou uma função de retorno de chamada aceitando o tema (no contexto) que retorna uma string.
  2. options (Object [opcional]):
    • options.defaultMatches (Boolean [opcional]): Como window.matchMedia() não esta disponível no servidor, retornamos uma correspondência padrão durante a primeira montagem. O valor padrão é false.
    • options.matchMedia (Function [opcional]) Você pode fornecer sua própria implementação de matchMedia. This can be used for handling an iframe content window.
    • options.noSsr (Boolean [opcional]): Padrão é false. Para realizar a reconciliação de renderização do lado do servidor, ele precisa renderizar duas vezes. Uma primeira vez sem nada e uma segunda vez com os filhos. Este ciclo de renderização de dupla passagem tem uma desvantagem. É mais lento. Você pode definir esse sinalizador para true se você não estiver fazendo a renderização do lado do servidor.
    • options.ssrMatchMedia (Function [optional]) You can provide your own implementation of matchMedia in a server-side rendering context.

Nota: Você pode alterar as opções padrão usando default props, este recurso pertence ao tema através da chave MuiUseMediaQuery.

Retornos

matches: Matches é true se o documento coincidir com a consulta de mídia, e false quando isso não ocorrer.

Exemplos

import React from 'react';
import useMediaQuery from '@material-ui/core/useMediaQuery';

export default function SimpleMediaQuery() {
  const matches = useMediaQuery('(min-width:600px)');

  return <span>{`(min-width:600px) matches: ${matches}`}</span>;
}