3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Reactで画像の遅延ロードするためのコンポーネント

Posted at

ReactでHooksとIntersection Observer API使って、プレースホルダー付きで画像の遅延読み込みするコンポーネントをだいぶ前に作った時のメモ。

使い方
<LazyImage src="https://your-image-url" />
import React, { useState, useRef, useEffect } from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
require('intersection-observer') // intersection-observer api polyfill

const Img = styled.img`
  transition: all 1s ease-in-out;

  @keyframes placeHolder {
    0% {
      background-position: -468px 0;
    }
    100% {
      background-position: 468px 0;
    }
  }

  ${props => props.imageLoaded
    || props.noPlaceholder
    || `
    animation-name: placeHolder;
    animation-duration: 1.5s;
    animation-fill-mode: forwards;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
    background: #f6f7f8;
    background: linear-gradient(to right, #eeeeee 8%, #dfdfdf 20%, #eeeeee 33%);
    background-size: 800px 104px;
    filter: blur(5px);
    position: relative;
  `}
`

function LazyImage({ src, ...props }) {
  const imageRef = useRef()
  const [imageLoaded, setImageLoaded] = useState(false)

  let observer

  useEffect(() => {
    observer = new IntersectionObserver(startLoading, { rootMargin: '50px' })
    if (!imageLoaded) {
      observer.observe(imageRef.current)
    }
    return () => observer.unobserve(imageRef.current)
  }, [])

  function startLoading(entries, object) {
    entries.forEach((entry) => {
      if (!entry.isIntersecting) return

      if (entry.intersectionRatio > 0) {
        observer.unobserve(entry.target)
      }

      if (!imageLoaded) {
        const downloadingImage = new Image()
        downloadingImage.onload = () => {
          if (imageRef.current) {
            imageRef.current.setAttribute('src', downloadingImage.src)
            setImageLoaded(true)
          }
        }

        downloadingImage.src = src
        object.unobserve(entry.target)
      }

      object.unobserve(entry.target)
    })
  }

  return (
    <Img
      {...props}
      alt="GOOD BOYE"
      ref={imageRef}
      imageLoaded={imageLoaded}
    />
  )
}

LazyImage.propTypes = {
  src: PropTypes.string,
  noPlaceholder: PropTypes.bool,
}

LazyImage.defaultProps = {
  src: '',
  noPlaceholder: false,
}

export default LazyImage
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?