Chapter 22無料公開

SkeltonとIntersectionObservableを組み合わせる

terrierscript
terrierscript
2021.05.09に更新

Intersection Observableを利用することでLazy Loadingのようなことが可能です。

これを組み合わせるのに最適なコンポーネントとしてSkeletonが用意あります。

Interection Observableについては本題ではないので、今回はuse-intersectionを組み合わせていきましょう

import { Box } from "@chakra-ui/react"
import React, { FC, useRef } from "react"
import { useIntersection } from "use-intersection"

export const LazyElement: FC<{}> = ({ children }) => {
  const ref = useRef<HTMLDivElement>(null)
  const intersecting = useIntersection(ref, {
    rootMargin: '250px',
    once: true,
  })

  return <div ref={ref}>
    <Skeleton isLoaded={intersecting}>
      {children}
    </Skeleton>
  </div>
}

使い方は下記のようになります。

const SomeItems = ({items}) => {
  return <>{items.map((item) => {
      return <LazyElement><Item item={item} /></LazyElement>
  })}
}

<Skeleton>のロード自体が重い場合は?

<Skeleton>{children}</Skeleton>の記述をすると、Skeletonは内部の要素の高さを計算してくれますが、その処理自体がボトルネックになることもあるでしょう。

そのような場合は下記のように事前に作成したSkeletonコンポーネントを用意すると解消されます。

const LoadingSkeleton = () => <Stack>
  <Skeleton height="20px" />
  <Skeleton height="20px" />
  <Skeleton height="20px" />
</Stack>

export const LazyElement: FC<{}> = ({ children, }) => {
  const ref = useRef<HTMLDivElement>(null)
  const intersecting = useIntersection(ref, {
    rootMargin: '250px',
    once: true,
  })

  return <div ref={ref}>
    {intersecting ? children : <LoadingSkeleton />}
  </div>
}

サンプル

下記にサンプルを記載します