You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React响应式布局开发中useEffect报Cannot read property 'style' of undefined错误

问题原因

你遇到的Cannot read property 'style' of undefined报错核心原因是DOM节点不存在时强行读取了节点的style属性,具体触发场景有三个:

  1. 你绑定了ref的<main>节点仅在宽度>650时渲染,当页面宽度<=650时,ref.current为null,此时第三个useEffect直接读取ref.current.children就会报错,后续滚动事件触发时读取不存在的节点样式也会报错
  2. 宽度判断逻辑存在1px的空档:宽度等于650时,两类视图都不会渲染,此时ref.current同样为null
  3. 滚动事件绑定后没有做节点存在性校验,即使对应DOM已经被销毁,滚动事件触发时依然会尝试修改节点样式
修复方案

按以下步骤修改即可解决问题:

  • 合并冗余的宽度状态,将screen和width合并为一个状态存储窗口宽度
  • 修复宽度判断的1px空档,统一判断逻辑
  • 所有操作DOM的位置前先校验节点是否存在
  • 给初始化获取宽度的useEffect添加空依赖,避免重复执行
  • 滚动事件回调中增加节点存在性校验,节点不存在时终止逻辑执行
修正后核心代码
import { useState, useEffect, useRef } from 'react';

export default function App() {
  // 服务端渲染兼容处理,纯客户端项目可直接写window.innerWidth
  const [width, setWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 0);
  const ref = useRef(null);

  const setImageLimitMovement = 1;
  const setTextLimitMovement = 4;
  const opacityRange = 400;
  const speed = 1;

  // 监听窗口宽度变化
  useEffect(() => {
    const handleResize = () => {
      setWidth(window.innerWidth);
    };
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  // 滚动动画逻辑
  useEffect(() => {
    // 节点不存在时直接终止逻辑
    if (!ref.current) return;
    
    const app = [...ref.current.children];
    const titles = app.filter((el) => el.matches(".titles"));
    const blocks = app.filter((el) => el.matches(".blocks"));
    const img = app.find((el) => el.matches("#passport"));

    // 校验需要用到的节点是否都存在
    if (!titles[0] || !titles[1] || !img || !blocks[0]) return;

    const centerPoints = blocks.map((blockEl, idx) => {
      const blockindex = idx + 1;
      const blockHeight = Math.floor(blockEl.getBoundingClientRect().height);
      const blockHalf = blockHeight / 2;
      return blockHeight * blockindex - blockHalf;
    });

    const changeBackground = () => {
      // 每次执行滚动逻辑前都校验节点存在性
      if (!titles[0] || !titles[1] || !img || !centerPoints[0]) return;
      
      const value = window.scrollY;
      titles[0].style.transform = `translateY(-${value * speed}px)`;
      
      if (centerPoints[0] > value) {
        img.style.transform = `translateX(-${value * (1 / setImageLimitMovement)}px)`;
        titles[1].style.transform = `translateX( ${0 + value / setTextLimitMovement}px)`;
        titles[1].style.opacity = value / opacityRange;
        return;
      }

      window.requestAnimationFrame(changeBackground);
    };
    window.addEventListener("scroll", changeBackground);
    return () => window.removeEventListener("scroll", changeBackground);
  }, [width]); // 依赖改为width,宽度变化时重新绑定逻辑

  return (
    <>
      {width >= 650 ? (
        <div id="section2">
          <main ref={ref}>
            <h1 id="title" className="titles">
              {posts.Title}
            </h1>
            <section id="block1" className="blocks"></section>
            <figure id="passport">
              <img
                alt="passport"
                src="https://cdn.britannica.com/87/122087-050-1C269E8D/Cover-passport.jpg"
              />
            </figure>
            <h2 id="text1" className="titles text1">
              Random Text 1
            </h2>
          </main>
        </div>
      ) : (
        <div style={{ height: "100vh", backgroundColor: "black" }}></div>
      )}
    </>
  );
}

内容的提问来源于stack exchange,提问作者Jay Modi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 11:15:03