Next.js结合Framer Motion使用window.innerWidth < 768报window未定义错求助
问题排查与修复方案
存在的问题
- 服务端渲染兼容性错误:Next.js 会在服务端预先渲染组件HTML,Node.js 环境不存在
window全局对象,你直接在组件顶层同步执行window.innerWidth会触发ReferenceError: window is not defined报错。 - 变量声明错误:你使用
const声明了MobileView变量,后续又对它重新赋值,const声明的常量不允许重新赋值,会触发语法报错。 - 缺少窗口变化监听:当前逻辑仅会在组件初始化时判断一次设备宽度,用户切换横竖屏、手动缩放窗口时,动画规则不会同步更新。
可运行修复示例
import React, { useEffect, useState } from "react"; import { useInView } from "react-intersection-observer"; import { motion, useAnimation } from "framer-motion"; export default function ValuesSection() { const controls = useAnimation(); const [ref, inView] = useInView(); // 初始化状态,服务端渲染阶段用默认值,避免访问window const [isMobile, setIsMobile] = useState(false); useEffect(() => { // 定义判断移动设备的方法 const checkIsMobile = () => { setIsMobile(window.innerWidth < 768); }; // 组件挂载到客户端后首次执行判断 checkIsMobile(); // 监听窗口大小变化,实时更新判断结果 window.addEventListener('resize', checkIsMobile); // 组件卸载时清理事件监听,避免内存泄漏 return () => window.removeEventListener('resize', checkIsMobile); }, []); // 根据设备类型动态返回动画配置 const motionVariants = isMobile ? {} : { visible: { y: 0, scale: 1 }, hidden: { y: 250, scale: 0 }, }; useEffect(() => { if (inView) { controls.start("visible"); } }, [controls, inView]); return ( <motion.div ref={ref} animate={controls} initial="hidden" variants={motionVariants} > Some content </motion.div> ) }
补充说明
如果不需要响应窗口变化,仅需要初始化时判断一次设备类型,可以去掉resize事件监听逻辑,仅在useEffect中执行一次宽度判断即可。
内容的提问来源于stack exchange,提问作者Mathias Riis Sorensen
相关产品推荐
相关产品推荐

