React で簡単に遅延読み込みを実装できるライブラリを作りました
はじめに
どうも、さぃと (@saitoeku3) です。
突然ですが、あなたは自作のライブラリを公開したことがありますか?
僕は公開したいと思いつつもなかなかできずに年を越してしまいそうだったので、思い切って公開しちゃいました。
ネタは最近よく使っている遅延読み込みと Gatsby.js + Contentful 関連の2つあったのですが、今回は前者の方です。(後者もそのうち公開します)
作ったもの
返り値の ref
を任意のエレメントの ref
に渡すだけで遅延読み込みをしてくれるカスタムフックを利用できるライブラリです。React での使用を想定しています。
今までにもいくつか遅延読み込みをしてくれるライブラリはあったのですが、コンポーネントベースで利用するものが多くて使いづらかったという問題を解決しています。(強引な押し売り)
特に差別化できると思っているのは、isLoaded
という読み込みが終わると false
から true
に切り替わる変数を使えるところで、プレースホルダーを出して UX を改善するときにも使えます。他にも CSS の background-image
に対応していたりと便利なライブラリになっています。
対応しているエレメントは img
、iframe
、video
、 audio
の4つで background-image
についてはその他の HTML エレメント全てで使えるはずです。
import React from 'react' import useLazyloadRef from 'use-lazyload-ref' const Component = ({ url }) => { const [ref, isLoaded] = useLazyloadRef() return ( <> {isLoaded || <Skeleton />} <img ref={ref} data-src={url}> </> ) }
内部実装
画面に入っているかの検知は IntersectionObserver
を ref
の使い方は「コールバック形式の ref」を使用しました。やっていることは割とシンプルで次のようになっています。
- マウント時に任意のエレメントを
IntersectionObserver
で監視させる - 画面に入ったことを
IntersectionObserver
が検知する - 任意のエレメントの
data-src
をsrc
に渡す - 読み込みが終わると
onload
で読み込みが終了したことを検知してisLoaded
をtrue
にする
ただし CSS の background-image
を遅延読み込みする場合は少し特殊なことをします。理由は CSS だと onload
で読み込みの検知ができないからです。そのため、次のように1度 img
を生成して img
で読み込んだ後に background-image
を更新するという手を取りました。
const url = target.dataset.src || '' const img = new Image() img.src = url img.onload = () => { target.style.backgroundImage = `url(${url})` setIsLoaded(true) }
参考
おわりに
今回は自作ライブラリの紹介と解説をしました。
フロントエンドの UX 改善やパフォーマンスチューニングに使えるものなので、そのあたりに興味のある方は実際に使ってみていただけると嬉しいです。不具合や質問があればすぐに対処するので連絡ください。
最後に GitHub でスターをつけていただけると励みになるのでお待ちしてます。