React滑块代码在CodeSandbox正常,本地Next.js项目报错TypeError
问题:Next.js项目中获取DOM元素offsetWidth报错,CodeSandbox正常运行
问题详情
我用React构建原生可拖拽滑块并想把它定位在屏幕中央,以下核心代码在CodeSandbox里能正常运行:
const windowWidth = window.innerWidth / 2; const itemWidth = track.firstChild.offsetWidth / 2; const offsetPercent = ((windowWidth - itemWidth) / window.innerWidth) * 100; track.style.left = `${offsetPercent}%`;
但把代码迁移到Next.js本地项目后,一直报错:TypeError: Cannot read properties of null (reading 'offsetWidth')。
报错原因及解决办法
1. 核心原因:DOM未挂载就执行代码
Next.js默认是服务端渲染(SSR),代码会在服务端先执行一遍,这时候浏览器DOM还没生成,track或者track.firstChild就是null,自然拿不到offsetWidth。而CodeSandbox是纯客户端渲染,不存在这个时机问题。
2. 正确解决方式:用useEffect确保DOM挂载后执行
把计算位置的代码放到useEffect钩子中,同时用useRef获取DOM元素,还要加判断避免null报错:
import { useEffect, useRef } from 'react'; export default function Slider() { const trackRef = useRef(null); // 用ref获取track元素 useEffect(() => { const track = trackRef.current; // 先判断元素是否存在,避免报错 if (!track || !track.firstChild) return; // 计算并设置位置 const calcPosition = () => { const windowWidth = window.innerWidth / 2; const itemWidth = track.firstChild.offsetWidth / 2; const offsetPercent = ((windowWidth - itemWidth) / window.innerWidth) * 100; track.style.left = `${offsetPercent}%`; }; // 初始化计算 calcPosition(); // 监听窗口大小变化,实时更新位置 window.addEventListener('resize', calcPosition); // 组件卸载时移除监听 return () => window.removeEventListener('resize', calcPosition); }, []); return ( <div ref={trackRef} className="track"> {/* 你的滑块子元素 */} </div> ); }
3. 额外注意:动态子元素的情况
如果track的子元素是通过条件渲染生成的(比如依赖某个状态),要把这个状态加到useEffect的依赖数组里,确保子元素出现后重新计算:
useEffect(() => { // ... 同上的计算代码 }, [yourDynamicState]); // 加入子元素依赖的状态
4. 临时测试方案:禁用组件SSR(不推荐)
如果只是想快速验证代码逻辑,可以用Next.js的dynamic导入禁用该组件的服务端渲染,但这会影响页面性能,不建议作为最终方案:
import dynamic from 'next/dynamic'; const Slider = dynamic(() => import('../components/Slider'), { ssr: false });
内容的提问来源于stack exchange,提问作者IamSebastn
相关产品推荐
相关产品推荐

