useMediaQuery
Este é um hook de consulta de mídia CSS 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.
- 🚀 É performático, ele observa o documento para detectar quando suas consultas de mídia mudam, em vez de pesquisar os valores periodicamente.
- 📦 1 kB gzipped.
- 🤖 Suporta a renderização do lado do servidor.
A paleta com funções de estilo.
Consulta de mídia simples
Você deve fornecer uma consulta de mídia ao primeiro argumento do hook. A string de consulta de mídia pode ser qualquer consulta de mídia CSS válida, por exemplo '(prefers-color-scheme: dark)'
.
import * as React from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
export default function SimpleMediaQuery() {
const matches = useMediaQuery('(min-width:600px)');
return <span>{`(min-width:600px) matches: ${matches}`}</span>;
}
⚠️ Você não pode usar 'print'
devido a limitação de navegadores, por exemplo, este bug presente no Firefox.
Usando auxiliares de ponto de quebra do Material-UI
Você pode usar os auxiliares 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>;
}
Como alternativa, você pode usar uma função de retorno, 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>;
}
Você pode usar json2mq para gerar uma string de consulta de mídia a partir de um objeto JavaScript.
Usando a sintaxe JavaScript
Você pode usar json2mq para gerar uma string de consulta de mídia a partir de um objeto JavaScript.
import * as React from 'react';
import json2mq from 'json2mq';
import useMediaQuery from '@mui/material/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 somente do lado do cliente
Para executar a hidratação no lado do servidor, o hook precisa renderizar duas vezes. Uma primeira vez com false
, o valor do servidor e uma segunda vez com o valor resolvido. Este ciclo de renderização de dupla passagem tem uma desvantagem. É mais lento. Você pode definir a opção noSsr
para true
se você estiver fazendo renderização somente no lado cliente.
const matches = useMediaQuery('(min-width:600px)', { noSsr: true });
ou pode ativar globalmente com o tema:
const theme = createTheme({
components: {
MuiUseMediaQuery: {
defaultProps: {
noSsr: true,
},
},
},
});
Renderização do lado servidor
⚠️ 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.
Por exemplo, no lado do servidor:
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, {
// O CSS estimado pelo navegador.
width: deviceType === 'mobile' ? '0px' : '1024px',
}),
});
const html = ReactDOMServer.renderToString(
<ThemeProvider
theme={{
props: {
// Modifica as opções padrão de useMediaQuery
MuiUseMediaQuery: { ssrMatchMedia },
},
}}
>
<App />
</ThemeProvider>,
);
// …
}
}
}
}
}
Certifique-se de fornecer a mesma implementação de mídia de correspondência customizada para o lado do cliente para garantir uma correspondência de hidratação.
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
:
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
API
useMediaQuery(query, [options]) => matches
Argumentos
query
(string | func): A string representing the media query to handle or a callback function accepting the theme (in the context) that returns a string.options
(object [optional]):
options.defaultMatches
(bool [optional]): Aswindow.matchMedia()
is unavailable on the server, we return a default matches during the first mount. O valor padrão éfalse
.options.matchMedia
(func [optional]): You can provide your own implementation of matchMedia. Isso pode ser usado para manipular uma janela iframe com conteúdo.options.noSsr
(bool [optional]): Defaults tofalse
. Para executar a hidratação no lado do servidor, o hook precisa renderizar duas vezes. Uma primeira vez comfalse
, o valor do servidor e uma segunda vez com o valor resolvido. Este ciclo de renderização de dupla passagem tem uma desvantagem. É mais lento. Você pode definir esta opção paratrue
se você estiver fazendo renderização somente no lado cliente.options.ssrMatchMedia
(func [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 * as 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>;
}