ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

useMediaQuery 深度指南:用 Match Media API 在 React 中响应式追踪视口与媒体查询状态

useMediaQuery 深度指南:用 Match Media API 在 React 中响应式追踪视口与媒体查询状态 前端【免费下载链接】usehooks-tsReact hook library, ready to use, written in Typescript.项目地址https://gitcode.com/gh_mirrors/us/usehooks-ts点击查看免费下载本文是 usehooks-ts 系列 hook 源码解析之一。useMediaQuery是 usehooks-ts 提供的一个轻量级 React Hook它基于浏览器原生的 Match Media APIwindow.matchMedia将 CSS 媒体查询的匹配结果封装成可响应式更新的 React 状态。在移动端适配、断点切换、主题偏好如prefers-color-scheme检测等场景中你只需一行调用即可拿到布尔值并随窗口尺寸变化自动刷新无需手动绑定resize事件或自行管理监听器生命周期。读完本文你将掌握useMediaQuery的完整用法、SSR 下的正确配置方式、其底层实现原理以及它与useScreen、useEventListener等兄弟 Hook 的协作关系。快速开始一行代码追踪视口断点useMediaQuery的核心用法极其简单传入一条合法的 CSS 媒体查询字符串返回一个boolean表示当前环境是否匹配该查询import { useMediaQuery } from usehooks-ts function Component() { const isSmallScreen useMediaQuery((max-width: 600px)) // 使用 isSmallScreen 根据屏幕尺寸条件化地应用样式或逻辑 return div{isSmallScreen ? 小屏 : 大屏}/div }当窗口尺寸跨越 600px 断点时isSmallScreen会随浏览器change事件自动更新组件随之重新渲染无需任何手动订阅。由于返回值就是布尔值它可以直接用于条件渲染、样式计算或驱动其他逻辑分支。仓库自带的官方示例位于 useMediaQuery.demo.tsx展示了另一个典型断点——以(min-width: 768px)判断视口是否达到平板/桌面宽度并将匹配结果渲染为一段描述文本import { useMediaQuery } from ./useMediaQuery export default function Component() { const matches useMediaQuery((min-width: 768px)) return ( div {The view port is ${matches ? at least : less than} 768 pixels wide} /div ) }API 签名与选项说明useMediaQuery的完整签名在 useMediaQuery.ts 中定义其类型与 JSDoc 注释如下type UseMediaQueryOptions { /** 在服务端运行时返回的默认值。default false */ defaultValue?: boolean /** 若为 true默认hook 会在初始化时读取一次媒体查询。SSR 场景应设为 false初始返回 options.defaultValue 或 false。default true */ initializeWithValue?: boolean } export function useMediaQuery( query: string, { defaultValue false, initializeWithValue true }: UseMediaQueryOptions {}, ): boolean参数类型默认值说明querystring必填需要追踪的 CSS 媒体查询字符串如(max-width: 600px)、(prefers-color-scheme: dark)options.defaultValuebooleanfalse服务端渲染SSR环境下 hook 返回的初始值也可用于水合hydration前的占位值options.initializeWithValuebooleantrue是否在初始化时立即读取一次媒体查询结果。SSR 场景应设为false避免服务端与客户端首帧渲染不一致导致水合警告SSR 与水合必须设置initializeWithValue: false这是官方文档中列出的第一条注意事项也是使用本 Hook 最容易踩坑的地方Note:如果在 SSR 上下文中使用此 Hook请将initializeWithValue选项设置为false。原因可以从源码实现中直接看出。useMediaQuery.ts 在模块顶层通过typeof window undefined判断运行环境const IS_SERVER typeof window undefinedgetMatches内部做了环境分流const getMatches (query: string): boolean { if (IS_SERVER) { return defaultValue } return window.matchMedia(query).matches }在服务端没有window对象window.matchMedia根本无法调用因此服务端只能返回defaultValue。而useState的初始值逻辑如下const [matches, setMatches] useStateboolean(() { if (initializeWithValue) { return getMatches(query) } return defaultValue })当initializeWithValue为true默认服务端首帧返回defaultValue客户端首帧会立即调用window.matchMedia(query).matches返回真实匹配结果。若两端初始值不一致例如defaultValue为false而客户端实际匹配为true就会产生 React 水合hydration不匹配警告严重时会导致样式闪烁。当initializeWithValue设为false两端在首次渲染时都返回defaultValue服务端与客户端首帧输出完全一致水合自然稳定真实的媒体查询结果会在挂载后的useIsomorphicLayoutEffect中通过handleChange()读取并更新。因此在 Next.js、Remix、Astro 等 SSR/SSG 框架中推荐写法是const isDesktop useMediaQuery((min-width: 1024px), { initializeWithValue: false, defaultValue: false, })defaultValue在这里兼具两个作用作为 SSR 阶段的返回占位值以及作为水合前初始渲染的兜底值。底层原理状态初始化 事件订阅 兼容层useMediaQuery的实现只依赖一个 React 状态与一个 effect逻辑非常紧凑完整源码见 useMediaQuery.ts。1. 状态初始化通过useState惰性初始化lazy initializer读取一次当前匹配结果保证组件首次渲染时状态就有值避免“先 false 后 true”的闪烁SSR 场景除外见上文。2. 事件订阅与清理核心 effect 使用useIsomorphicLayoutEffect包裹依赖数组为[query]其内部流程是useIsomorphicLayoutEffect(() { const matchMedia window.matchMedia(query) // 首次客户端加载以及 query 变化时触发 handleChange() // 使用已废弃的 addListener/removeListener 以兼容 Safari 14#135 if (matchMedia.addListener) { matchMedia.addListener(handleChange) } else { matchMedia.addEventListener(change, handleChange) } return () { if (matchMedia.removeListener) { matchMedia.removeListener(handleChange) } else { matchMedia.removeEventListener(change, handleChange) } } }, [query])挂载后立即调用一次handleChange()确保首帧同步到真实媒体查询结果这也正是initializeWithValue: false场景下状态被“修正”的时点随后订阅change事件窗口尺寸变化或媒体查询条件翻转时handleChange会重新计算getMatches(query)并setMatches触发响应式更新清理函数在组件卸载或query变化时移除监听器杜绝内存泄漏。依赖[query]意味着传入不同的媒体查询字符串时Hook 会自动解绑旧查询、绑定新查询无需手动重置。3. Safari 14 兼容层这是官方文档中的第二条注意事项源码中同样有明确注释#135指仓库对应 issueNote:在 Safari 14 之前MediaQueryList基于EventTarget实现只支持addListener/removeListener来监听媒体查询。如果你不需要支持这些版本可以移除这些检查。因此在订阅与清理两个位置源码都采用了“能力检测”式的双分支写法若matchMedia.addListener存在老版本 Safari走addListener/removeListener否则使用标准的addEventListener(change, ...)/removeEventListener(change, ...)。这套兼容逻辑确保 Hook 在老版本浏览器与标准实现之间都能正常工作若你的项目最低目标浏览器已高于 Safari 14删掉这两处分支也不会影响功能。为什么用useIsomorphicLayoutEffect而不是useEffectuseMediaQuery没有直接使用useEffect而是依赖了兄弟 HookuseIsomorphicLayoutEffect。其定义位于 useIsomorphicLayoutEffect.ts实现异常简洁export const useIsomorphicLayoutEffect typeof window ! undefined ? useLayoutEffect : useEffect客户端环境下它等价于useLayoutEffect在浏览器完成布局layout与绘制paint之前同步执行订阅逻辑可避免首帧出现“先渲染默认值、再跳变到真实值”的可见闪烁服务端环境下React 会警告useLayoutEffect不可用因此自动降级为useEffect保证 SSR 渲染不报错。这正是“isomorphic同构”的含义同一份代码在客户端与服务端都能安全运行。同类设计也出现在useScreen、useEventListener等 Hook 中详见下文。实战组合与 useScreen、useEventListener 的协作在 README.md 的 Hook 清单中useMediaQuery被定位为“使用 Match Media API 追踪媒体查询状态”它属于“响应式追踪类”能力家族与下面几个 Hook 分工互补useScreenuseScreen.ts追踪window.screen的尺寸与属性width、height、availHeight、orientation等并提供debounceDelay选项对 resize 更新做防抖。它关注的是“物理屏幕信息”而useMediaQuery关注的是“是否命中某条查询规则”两者可配合实现“大屏才展示某模块、且需要精确屏幕参数”的复杂场景。useScreen同样采用IS_SERVER环境判断与initializeWithValue选项与useMediaQuery的 SSR 设计一脉相承。useEventListeneruseEventListener.ts通过 TypeScript 重载同时支持WindowEventMap、HTMLElementEventMap、DocumentEventMap与MediaQueryListEventMap四类事件目标。如果你需要在一个MediaQueryList上同时监听change之外的逻辑可以直接把useMediaQuery的内部订阅模式替换为useEventListener(change, handler, matchMediaRef)两者事件模型完全互通。这也从侧面印证了useMediaQuery底层就是“一次matchMedia调用 一次change订阅”的标准实现。一个典型组合示例——深色模式偏好检测配合屏幕断点import { useMediaQuery } from usehooks-ts function AdaptiveTheme() { const prefersDark useMediaQuery((prefers-color-scheme: dark)) const isDesktop useMediaQuery((min-width: 1024px)) // prefersDark 决定主题isDesktop 决定布局密度 return div>赞分享前端【免费下载链接】usehooks-tsReact hook library, ready to use, written in Typescript.项目地址https://gitcode.com/gh_mirrors/us/usehooks-ts点击查看免费下载相关推荐Material UI useMediaQuery 深入解析用 React Hook 实现响应式媒体查询Material UI useMediaQuery 深入解析用 React Hook 实现响应式媒体查询 本篇指南围绕 MUI Material 的 useM前端UI组件设计系统airi 项目中的 VueUse useMediaQuery 响应式媒体查询实战指南airi 项目中的 VueUse useMediaQuery 响应式媒体查询实战指南 本篇指南以 VueUse 的 useMediaQuery 组合式函数为核心AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染react-use 中的 useMedia用 React Hook 优雅追踪 CSS 媒体查询状态react use 中的 useMedia用 React Hook 优雅追踪 CSS 媒体查询状态 useMedia 是 react use 提供的一个传感器前端上一篇Vector v0.21.2 补丁版本深度解析回归修复清单与 AWS 凭证加载超时配置下一篇Activepieces 定时降级席位上限机制解析scheduledUsersLimit 的派生、执行与自愈设计创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表