[開源推薦]:一個輕量的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留言或者在文章底部評論,我都會看而且回覆。
但願你們多多支持呀😃

相關文章
相關標籤/搜索