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
相关产品推荐
相关产品推荐

