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. The media query string can be any valid CSS media query, e.g. '(prefers-color-scheme: dark)'
.
⚠️ 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
You can use MUI's breakpoint helpers as follows:
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.
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
Try relying on client-side CSS media queries first. For instance, you could use:
If none of the above alternatives are an option, you can proceed reading this section of the documentation.
First, you need to guess the characteristics of the client request, from the server. You have the choice between using:
- 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.
Finally, you need to provide an implementation of matchMedia to the useMediaQuery
with the previously guessed characteristics. Using css-mediaquery to emulate matchMedia is recommended.
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, {
// O CSS estimado pelo navegador.
width: deviceType === 'mobile' ? '0px' : '1024px',
}),
});
const theme = createTheme({
components: {
// Modifica as opções padrão de useMediaQuery
MuiUseMediaQuery: {
defaultProps: {
ssrMatchMedia,
},
},
},
});
const html = ReactDOMServer.renderToString(
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>,
);
// …
}
Make sure you provide the same custom match media implementation to the client-side to guarantee a hydration match.
Migrando de withWidth()
The withWidth()
higher-order component injects the screen width of the page. You can reproduce the same behavior with a useWidth
hook:
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 [opcional]): Padrãofalse
. 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.
Note: You can change the default options using the default props
feature of the theme with the MuiUseMediaQuery
key.
Retornos
matches
: Matches is true
if the document currently matches the media query and false
when it does not.
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>;
}