useMediaQuery
这是React的CSS媒体查询钩子。 它侦听与CSS媒体查询的匹配。 它允许根据查询是否匹配来呈现组件。
一些重要特点:
- ⚛️它有一个惯用的React API。
- 🚀它具有高性能,它会观察文档以检测其媒体查询何时发生更改,而不是定期轮询值。
- 📦 1kB 已压缩的包。
- 🤖它支持服务器端渲染。
简单的媒体查询
您应该为挂钩的第一个参数提供媒体查询。 The media query string can be any valid CSS media query, e.g. '(prefers-color-scheme: dark)'
.
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.
使用Material-UI的断点助手
You can use Material-UI'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>;
}
Alternatively, you can use a callback function, accepting the theme as a first argument:
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>;
}
⚠️ There is no default theme support, you have to inject it in a parent theme provider.
使用JavaScript语法
You can use json2mq to generate media query string from a JavaScript object.
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>;
}
测试
You need an implementation of matchMedia in your test environment.
For instance, jsdom doesn't support it yet. You should polyfill it. Using css-mediaquery to emulate it is recommended.
import mediaQuery from 'css-mediaquery';
function createMatchMedia(width) {
return query => ({
matches: mediaQuery.match(query, { width }),
addListener: () => {},
removeListener: () => {},
});
}
describe('MyTests', () => {
beforeAll(() => {
window.matchMedia = createMatchMedia(window.innerWidth);
});
});
服务器端呈现
⚠️ Server-side rendering and client-side media queries are fundamentally at odds. Be aware of the tradeoff. The support can only be partial.
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. Parse the user agent string of the client to extract information. Using ua-parser-js to parse the user agent is recommended.
- Client hints. Read the hints the client is sending to the server. Be aware that this feature is not supported everywhere.
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, {
// 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>,
);
// …
}
Make sure you provide the same custom match media implementation to the client-side to guarantee a hydration match.
迁徙自 withWidth()
withWidth()
高阶组件注入页面的屏幕宽度。 您可以对 useWidth
钩子重用相同的操作:
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
API
useMediaQuery(query, [options]) => matches
参数
query
(String | Function): 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
(布尔值 [optional]): 作为window.matchMedia()
在服务器上不可用, 我们在第一次安装时返回默认匹配。 默认值为false
。options.matchMedia
(Function [optional]) You can provide your own implementation of matchMedia. This can be used for handling an iframe content window.options.noSsr
(Boolean [optional]): 默认值为false
。 为了执行服务器端呈现协调,它需要呈现两次。 第一次没有任何东西,第二次与孩子们在一起。 这种双遍渲染周期有一个缺点。 It's slower. You can set this flag totrue
if you are not doing server-side rendering.options.ssrMatchMedia
(Function [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.
返回结果
matches
:如果文档当前能够匹配这个媒体查询,Matches 是 true
,否则为 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>;
}