一般我们写一个曝光组件,可能会这么写
const ExposureWrapper = function (props: IProps) {
const ioRef = React.useRef();
if(!ioRef.current){
ioRef.current = new IntersectionObserver(handleVisibilityChange);
}
const io = ioRef.current;
const dom = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
dom.current && io?.observe(dom.current);
return () => {
if (dom.current) {
io?.unobserve(dom.current);
io?.disconnect();
}
};
}, []);
return <div ref={dom}>{props.children}</div>
}
其实这样也可以用,一般不会有问题。
但是为了追求更好的性能,我们可以进行一些优化。
在上面这个曝光组件中,我们每使用 ExposureWrapper 包裹一次别的组件,就会去 new 一个 IntersectionObserver 来观察 dom 对象。
但实际上,我们只需要一个 observer 对象,就可以用它去观察多个 dom 对象。🔥🔥🔥
developer.mozilla.org/en-US/docs/…
这样做会更快吗?很明显从直觉上是的,这里也有一些文章论证了这一点。
stackoverflow.com/questions/5…
那么,怎么实现ExposureWrapper组件共用一个 observer 呢?这个也简单,我们在 react 之外进行初始化一个单例就好了,这里注意兼容下 ssr。
为了方便呢,我们可以直接使用 intersection-observer-admin 这个库, 然后修改上面的代码
import IntersectionObserverAdmin from 'intersection-observer-admin';
const intersectionObserverAdmin = new IntersectionObserverAdmin();
const ExposureWrapper = function (props: IProps) {
const dom = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
dom.current && intersectionObserverAdmin.addEnterCallback(dom.current, enterCallback);
return () => {
if (dom.current) {
intersectionObserverAdmin.unobserve(element, observerOptions);
}
};
}, []);
return <div ref={dom}>{props.children}</div>
}