React Hooks媒体查询问题:reduced-motion钩子中window对象未定义
解决React Hook中检测Reduced Motion时window未定义的问题
先看你代码里的几个核心问题:
windowRef初始化后从未赋值,始终为null,强制访问windowRef.current!会直接抛出错误- 依赖数组里传入
window没有意义,且在SSR(服务端渲染)场景下,window本身就不存在 matchMedia的查询字符串缺少闭合括号,属于语法错误
下面是修正后的完整Hook,同时补上了监听媒体查询动态变化的逻辑(用户可能在浏览器设置中修改动画偏好):
import { useEffect, useState } from "react"; /** * Checks if the browser is running on reduced motion * @returns true if the browser is running on reduced motion */ const usePrefersReducedMotion = (): boolean => { // SSR环境下初始值设为false,可根据实际需求调整 const [prefersReducedMotion, setPrefersReducedMotion] = useState(false); useEffect(() => { // 先判断是否处于浏览器环境 if (typeof window === 'undefined') return; const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)"); // 定义状态更新函数 const updateStatus = () => { setPrefersReducedMotion(mediaQuery.matches); }; // 设置初始状态 updateStatus(); // 监听媒体查询变化 mediaQuery.addEventListener('change', updateStatus); // 组件卸载时移除监听,避免内存泄漏 return () => { mediaQuery.removeEventListener('change', updateStatus); }; }, []); // 空依赖数组,仅在组件挂载时执行一次 return prefersReducedMotion; }; export default usePrefersReducedMotion;
关键说明:
- 用
typeof window === 'undefined'做环境判断,兼容Next.js、Gatsby等SSR/SSG场景 - 直接在useEffect中使用
window.matchMedia,客户端挂载阶段window已存在,无需额外ref存储 - 添加
change事件监听,确保用户修改浏览器动画设置时,状态能同步更新 - 组件卸载时清理监听事件,避免潜在的内存泄漏问题
内容的提问来源于stack exchange,提问作者feh1000000
相关产品推荐
相关产品推荐

