지연 로딩 이미지 - [2/2]

요약



이전 게시물에서 이미지의 저해상도 버전과 고해상도 버전에 대한 두 가지 소스를 받는 React 구성 요소 이미지를 빌드했습니다. 다운로드가 완료되는 즉시 후자로 대체되는 전자를 표시합니다.

Repo 📑

추상적인



추가 성능 향상은 구성 요소가 표시될 때만 고해상도 이미지 다운로드를 시작하는 것입니다.
여전히 최신 React에 대한 관점에서 HTML 요소와 연결된 ref를 받은 후 IntersectionObserver API를 사용하여 요소가 보기에 있는지 평가하는 사용자 지정 후크를 빌드합니다.

프로세스



이전에 만든 해당 폴더에 후크를 추가합니다.

touch src/hooks/useIntersectionObserver.js


IntersectionObserver는 후크가 인수로 받는 useEffect에 따라 실행이 달라지는 elementRef에서 인스턴스화되어야 합니다. 이것은 사용 중에 다른 참조가 조건부로 제공되는 경우 후크의 기능이 응답하는 데 필요합니다.

진행하는 한 가지 방법은 후크 자체에서 선언된 ref에 IntersectionObserver를 바인딩하는 것입니다. 이런 식으로 후크를 사용하여 구성 요소를 마운트 해제할 때 React는 앞서 언급한 항목을 정리합니다ref.

IntersectionObserver 콜백에서 관찰되는 항목을 설정하는 것으로 충분합니다. 이렇게 하면 외부에서 쉽게 찾을 수 있습니다useEffect.


useIntersectionObserver.js



import { useRef, useEffect, useState } from 'react'

const useIntersectionObserver = elementRef => {
  const observer = useRef()
  const [entry, setEntry] = useState()

  const options = {
    threshold: 0.1,
    root: null,
    rootMargin: '0%',
  }

  const updateEntry = entries => {
    setEntry(entries[0])
  }

  useEffect(() => {
    const node = elementRef?.current
    if (!node) return

    if (observer.current) observer.current.disconnect()

    observer.current = new IntersectionObserver(updateEntry, options)

    const { current: currentObserver } = observer

    currentObserver.observe(node)

    return () => currentObserver.disconnect()
  }, [elementRef])

  return { isVisible: !!entry?.isIntersecting, entry }
}

export default useIntersectionObserver


뷰에 구성 요소가 있는지 여부를 나타내는 부울이 반환됩니다.

There are two observer.current.disconnect(). The first is executed only if the observer was already active but under observation on a different elementRef. In the second case, the disconnection occurs in the cleanup phase of the useEffect which, by extension, uniquely corresponds to the moment in which the component that makes use of the hook is removed from the DOM



For the purposes of this demo the hook always refers to the whole view. However, it is not difficult to take a second options argument and pass it into the IntersectionObserver instance (remember to add it to the useEffect dependencies)


The use in the <Image> component (the same as in the previous post) is immediate. I declare a ref ( imageRef ) and bind it to the root element of the component ( div.wrapper ). The same ref is supplied to the useIntersectionObserver hook which returns isVisible

Conditionally showing the second <img> tag, that is the one associated with the high-resolution image, you will get that the feature implemented in the previous post is used only when the element enters view. In the meantime, the user is shown the low-resolution image


Image.js(*는 이전 항목의 변경 사항을 나타냄)



import { useRef } from 'react'
import useImageOnLoad from '../hooks/useImageOnLoad'
import useIntersectionObserver from '../hooks/useIntersectionObserver'

const Image = ({ width = '100%', height = '100%', lowResSrc, highResSrc }) => {
  const { handleImageOnLoad, transitionStyles } = useImageOnLoad()

  const imageRef = useRef() // *
  const { isVisible } = useIntersectionObserver(imageRef) // *

  const styles = {
    wrapper: {
      position: 'relative',
      width,
      height,
    },
    image: {
      position: 'absolute',
      width: '100%',
      height: '100%',
      objectPosition: 'center center',
      objectFit: 'cover',
    },
  }

  const lowResStyle = {
    ...styles.image,
    ...transitionStyles.lowRes,
  }
  const hightResStyle = {
    ...styles.image,
    ...transitionStyles.highRes,
  }

  return (
    <div style={styles.wrapper} ref={imageRef}>
      <img src={lowResSrc} style={lowResStyle} />
      {isVisible && ( // *
        <img
          src={highResSrc}
          style={hightResStyle}
          onLoad={handleImageOnLoad}
        />
      )}
    </div>
  )
}

export default Image


원하는 효과가 있는지 확인하는 가장 간단한 방법은 이미지를 화면 밖으로 이동하는 것입니다.


App.js(세부정보)



<div style={{ position: 'relative', height: '200vh' }}>
  <div style={{ position: 'absolute', bottom: 0 }}>
    <ImageIO
      width={600}
      height={400}
      lowResSrc={srcTuple[0]}
      highResSrc={srcTuple[1]}
    />
  </div>
</div>


개발자 도구의 네트워크 탭에서 저해상도 이미지 다운로드가 가능한 한 빨리 수행되는 방법을 확인할 수 있습니다. 반면에 고해상도 이미지의 경우 컴포넌트가 시야에 있을 때만 시작됩니다.




읽어 주셔서 감사합니다. 다음 게시물에서 계속 진행 중입니다.

Repo 📑

당신이 그것을 좋아한다면, 연락하자
🐙

좋은 웹페이지 즐겨찾기