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

React中使用IntersectionObserver时ref.current为何始终为null?

React中IntersectionObserver监听多个ref时ref.current始终为null的原因及解决办法

核心原因

你遇到的问题本质是时机不匹配:

  • 在fetchData的回调里,你刚通过set data更新了状态,紧接着就创建ref并访问ref.current——但此时组件还没完成重新渲染,对应的<video>元素还没挂载到DOM上,ref还没和DOM元素建立关联,所以current自然是null。
  • 另外,你在循环里直接用createRef创建ref的方式存在隐患:createRef每次调用都会生成新的ref对象,后续组件重新渲染时可能出现ref与DOM元素不匹配的问题。

解决办法

办法一:监听数据变化,在DOM渲染完成后初始化Observer

把Observer的初始化逻辑拆分到监听data的useEffect中,确保DOM已经渲染完成、ref已绑定到对应元素:

const [data, setData] = useState([]);
const refs = useRef([]);

// 初始化数据
useEffect(() => {
  fetchData().then(results => {
    setData(results);
    // 初始化ref数组,用useRef持久化保存
    refs.current = results.map(() => createRef());
  }).catch(error => {
    alert("error");
  });
}, []);

// 数据更新后,DOM渲染完成再设置Observer
useEffect(() => {
  if (data.length === 0) return;

  const observer = new IntersectionObserver(entries => {
    // 这里写你的交集回调逻辑
  });

  refs.current.forEach(ref => {
    if (ref.current) {
      observer.observe(ref.current);
    }
  });

  return () => {
    refs.current.forEach(ref => {
      if (ref.current) {
        observer.unobserve(ref.current);
      }
    });
  };
}, [data]); // 依赖data,数据更新时触发

// 渲染部分
return (
  <div>
    {data.map((item, index) => (
      <video ref={refs.current[index]} key={index} />
    ))}
  </div>
);

办法二:使用回调Ref(更推荐)

回调Ref可以在元素挂载/卸载时直接触发逻辑,不需要依赖useEffect的时机,逻辑更可靠:

const [data, setData] = useState([]);
const observerRef = useRef(null);
const refs = useRef([]);

// 初始化Observer
useEffect(() => {
  observerRef.current = new IntersectionObserver(entries => {
    // 这里写你的交集回调逻辑
  });

  return () => {
    observerRef.current?.disconnect();
  };
}, []);

// 初始化数据
useEffect(() => {
  fetchData().then(results => {
    setData(results);
  }).catch(error => {
    alert("error");
  });
}, []);

// 回调Ref处理函数
const handleVideoRef = (element, index) => {
  const observer = observerRef.current;
  if (!observer) return;

  // 旧元素存在则取消监听
  if (refs.current[index]) {
    observer.unobserve(refs.current[index]);
  }

  // 新元素存在则添加监听
  if (element) {
    observer.observe(element);
  }

  // 更新ref数组
  refs.current[index] = element;
};

// 渲染部分
return (
  <div>
    {data.map((item, index) => (
      <video ref={el => handleVideoRef(el, index)} key={index} />
    ))}
  </div>
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:57:19