react-intersection-observer多组件ref绑定报错问题求解
react-intersection-observer 函数组件绑定监听报错解决方案
报错原因
- React 函数组件默认不支持直接接收
ref属性,直接传入的ref无法挂载到组件内部的真实DOM节点,因此会抛出警告。 - 你当前的写法只声明了1个
ref对象,就算解决了ref传递问题,这个ref也会被后渲染的组件覆盖,最终只能监听到最后一个板块的视口状态,无法同时对3个板块生效。
最优实现方案(无冗余代码、无需修改原有业务组件)
直接封装一个通用的视口监听包裹组件,所有入场触发逻辑统一维护,需要加效果的板块直接套一层即可:
- 新建通用包裹组件
InViewWrapper.jsx
import { useInView } from 'react-intersection-observer'; const InViewWrapper = ({ children, className = '' }) => { const { ref } = useInView({ triggerOnce: true, threshold: 0.2, // 不建议设为1,1要求元素100%进入视口才触发,快速滚动时容易漏触发,0.2代表元素露出20%即可触发 onChange: (inView, entry) => { if (inView) entry.target.classList.add('in-view'); } }); return ( <div ref={ref} className={className}> {children} </div> ); }; export default InViewWrapper;
- 在首页组件中用包裹组件套住需要监听的三个板块即可,不需要修改
About/PortfolioList/ContactForm任何内部代码:
import React from 'react'; import Header from "../../components/header/header.component"; import About from "../../components/about/about.component"; import PortfolioList from "../../components/portfolio-list/portfolio-list.component"; import ContactForm from "../../components/contact-form/contact-form.component"; import InViewWrapper from "../../components/common/InViewWrapper"; // 按你的实际路径引入 const HomePage = () => { return ( <div> <Header/> <main className="main"> <InViewWrapper> <About /> </InViewWrapper> <InViewWrapper> <PortfolioList /> </InViewWrapper> <InViewWrapper> <ContactForm /> </InViewWrapper> </main> </div> ); }; export default HomePage;
补充说明
如果不想要额外的包裹DOM节点,可以给三个业务组件加
React.forwardRef做ref透传,把传入的ref绑定到组件自身的根DOM节点上。但这种方案需要修改每个业务组件的代码,后续调整逻辑也要逐个改动,维护成本远高于通用包裹组件的方案,不推荐使用。
内容的提问来源于stack exchange,提问作者Andrei Teodorescu
相关产品推荐
相关产品推荐

