高性能曝光组件

141 阅读1分钟

一般我们写一个曝光组件,可能会这么写

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/…

这样做会更快吗?很明显从直觉上是的,这里也有一些文章论证了这一点。

www.bennadel.com/blog/3954-i…

stackoverflow.com/questions/5…

github.com/snewcomer/i…

那么,怎么实现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>
 }