[开源推荐]:一个轻量的React懒加载组件,冰冰用了都说6~

前言

现现在前端React生态圈已有很多优秀的懒加载组件,好比react-lazy-loadreact-lazy-mount等,可是它们并无实现一个组件彻底的懒加载,当DOM没有出如今视口中时,它们会先渲染出一部分,等到出如今视口中才会渲染要懒加载的目标,大多数基本都是图片懒加载,虽然已经知足了绝大多数要求,可是过程并非很完美。而真正实现组件懒加载的开源库,仍是经过scroll事件监听出如今窗口中的DOM,性能并非很优秀,笔者所开源的这个组件既不用使用scroll事件,也能实现组件懒加载。javascript

IntersectionObserver

这个组件所依赖的API是IntersectionObserver,关于这个API掘金已有很多文章来描述讲解了,我这里再简单描述一下:监听一个DOM元素,如果这个DOM元素出如今你规定的视口中(通常都为window窗口),调用指定的回调函数。可是我已看到的全部文章只是使用原生JS的方法来说解怎么使用。
好比:html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
    <script> const callback = (entries) => { entries.forEach((item) => { const isIntersecting = item.isIntersecting; if (isIntersecting) { const image = new Image(); image.src = "http://xxxx"; item.target.appendChild(image); } }); }; const io = new IntersectionObserver(callback); const container = document.querySelector(".container"); [...container.children].forEach((ele) => { ele.observe(ele); }); </script>
  </body>
</html>
复制代码

上面代码是我大概写的一个使用教程,中只要container中一个子元素出如今视口中,就加载出一张图片。可是这种写法以及思路用在React或者Vue中使用是不符合规范的。那么咱们该如何在React中使用呢?前端

组件思路

在React中拿到真实DOM

众所周知,React中是虚拟DOM,也就是一个对象,React内部用这个虚拟DOM渲染成真实的DOM,咱们在React组件内部如何不是操做DOM的话,通常是不会用到真实DOM的,而IntersectionObserver必须监听真实的DOM才能够,那怎么办呢?
这时候Ref就出场了,Ref挂到一个ReactDOM上能够帮助咱们拿到当前DOM的全部信息,包括真实DOM。java

const Example = () => {
    const domRef  = useRef();
    return( 
      <div ref={domRef}> { list.map(item=>(<div>{item}</div>)) } </div>
    )
  }
复制代码

利用这个特性咱们就能够拿到div的全部信息,包括它的子元素,这样咱们就能够经过IntersectionObserver来监听它全部的子元素是否出如今视口中。 那么问题来了,监听的元素都是已经被渲染出来的元素,那么还怎么懒加载呢?接下来这个思路就是step by stepreact

step by step

咱们先来看两个组件:git

const LazyList = (props) => {
  const [renderCont,setRenderCount] = useState(2)
  const children = props.children;
  const renderList = useMemo(()=>{
    return children.slice(0,renderCont)
  },[children,renderCont])
  useEffect(()=>{
  //...
  },[renderCont])
  return(
   <div>{renderList}</div>
  )
}

const Example = () => {
  return(
  	<LazyList> {list.map(item=>{ <div>111</div> })} </LazyList>
  )
}
复制代码

LazyList这个组件中,渲染children中的renderCont个,renderList一变化,在useEffect中的回调函数中经过ref拿到真实DOM,进行监听。github

提早渲染第renderCont + 1个DOM

上边咱们可以先渲染renderCont个DOM,可是如何进行懒加载呢?就是当renderCont中最后一个出如今视图中时,渲染第renderCont + 1个DOM,setRenderCount(renderCont + 1),这里是在IntersectionObserver回调函数中进行。循环往复,就实现了组件懒加载。web

效果


注意看控制台的DOM区域,初始渲染出两个,每次下拉渲染出来的两个出线在试图中,后续两个DOM就渲染出来了,视觉效果上也不会出现中断的感受。npm

最后

图示是我我的项目用来演示的,这个组件刚刚开源,目前我司咱们部门3个项目已经在生产环境使用了,没有任何问题。而且功能只为实现长列表懒加载,对于须要一次性渲染大量数据可是不须要彻底展现的业务比较契合,还未暴露接口指示渲染到第几个DOM,因此有一个功能并不支持:DOM渲染的回调函数,也就是暴露出渲染到了第几个DOM,目前正在完善这个功能,下个版本会上线。
此组件在web端和移动端都支持,而且引入了IntersectionObserverpolyfill,包的整体积为4.5KB。 具体代码以及逻辑看github吧~
github地址:点击这里
安装:markdown

npm i lazylist-react
 // or
 yarn add lazylist-react
复制代码

任何疑问均可以在githubissus留言或者在文章底部评论,我都会看而且回复。
但愿你们多多支持呀😃