useRef, IntersectionObserver 무한스크롤 구현하기

제이밍·2021년 8월 7일
3
post-thumbnail
post-custom-banner

useRef 로 특정 Dom 선택하기!

우리가 그동안 javascript 에서 Dom을 선택하기 위해선 getElementById 혹은 querySelector과 같은 함수를 사용해왔습니다

하지만 리액트에서 우리는 DOM을 직접 선택해야 하는 상황이 올때 무엇을 사용할까요?!

바로 ref 라는 것을 사용합니다.

특히 함수형 컴포넌트에서는 ref를 사용하기 위해 useRef 라는 Hook함수를 사용 합니다!

예시를 통해 useRef의 기능을 알아봅시다!

리액트 DOC에 정의된 useRef의 의미

useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환합니다.

const nameInput = useRef();

const onClick = () => {
    nameInput.current.focus();
}

return(
    <input ref={nameInput} />
    <button onClick={onClick}>클릭</button>
)
  1. 원하는 위치에 ref={} 형태로 작성
  2. 포커스를 잡는다고 하면 nameInput.current 을 가져와 focus() 시켜준다.
  const observer = useRef();
  
  const ElementRef = useCallback(
    // console.log(node) ref={ElementRef} 의 요소들을 전부 가져온다.
    // <div>TEST</div>
    node => {
    // Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르키게 됩니다.
     if(node) observer.current.observe(node);
    [],
  );
  
  return <div ref={ElementRef}>TEST</div>
  1. useCallback함수를 사용하면 node를 가지고 내부 로직을 설계할 수 있습니다.
  2. observe() 메서드로 IntersectionObserver 객체가 관찰할 엘리먼트 목록에 단일 엘리먼트를 추가합니다

본질적으로 useRef는 .current 프로퍼티에 변경 가능한 값을 담고 있는 “상자”와 같습니다.
만약

를 사용하여 React로 ref 객체를 전달한다면,
React는 모드가 변경될 때마다 변경된 DOM 노드에 그것의 .current 프로퍼티를 설정할 것입니다.

(useRef는 매번 렌더링을 할 때 동일한 ref 객체를 제공함!)

IntersectionObserver ?? 무한스크롤 알아야하는 교차로 관찰자 API!

하나의 옵저버 객체는 단일한 threshold와 root를 가지지만 복수의 타겟 엘리먼트의 가시성 변화를 관찰할 수 있습니다.

(MDN Docs의 정의는 언제나 내게 너무 어려운 것.. ㅠㅠ)

쉬운말로 표현하자면 뷰포트와 설정한 요소의 교차점을 관찰하여 요소가 뷰포트에 노출된 여부를 알 수 있게 해줍니다.

new IntersectionObserver(callback[, options]);

메소드

  • IntersectionObserver.disconnect()

    IntersectionObserver 가 어떤 대상이라도 감시하는 것을 중지합니다.
  • IntersectionObserver.observe()

    IntersectionObserver 객체가 관찰할 엘리먼트 목록에 단일 엘리먼트를 추가합니다.
  • IntersectionObserver.takeRecords()

    모든 감시되는 대상의 배열 (IntersectionObserverEntry) 을 리턴합니다.
  • IntersectionObserver.unobserve()

    특정 대상 요소를 감시하는 것을 중지합니다.
  const observer = useRef();
  
  const ElementRef = useCallback(
    // console.log(observer.current) 현재 관찰되고 있는 요소 
    node => {
      if (observer.current) observer.current.disconnect();
      // 최근 observer를 갖기위해 이전 observer disconnect 해주기
      observer.current = new IntersectionObserver(entries => {
        // entries는 아래 설명참조
        if (entries[0].isIntersecting && hasMore) {
          setPageNumber(prevPageNumber => prevPageNumber + 1);
        }
      });
      
     if(node) observer.current.observe(node);
     // 노드가 있으면 observer.current를 observe 해준다.
    [],
  );
  
  return (
      {data.map((item)=> <div>{item}<div>)}
  );

entries

image

entries는 IntersectionObserverEntry 인스턴스의 배열로 다음과 같은 프라퍼티(속성)을 갖습니다.

  • boundingClientRect: 관찰 대상의 경계 사각형 정보(DOMRectReadOnly)
  • intersectionRect: 관찰 대상의 교차한 영역 정보(DOMRectReadOnly)

    반환값이 1이면 isIntersection이 ture , 0 이면 false를 나타낸다.
  • intersectionRatio: 관찰 대상의 교차한 영역 백분율(intersectionRect 영역에서 boundingClientRect 영역까지 비율, Number)
  • isIntersecting: 관찰 대상의 교차 상태로 전환되었는데의 여부를 나타냄(Boolean)주로 대상 요소의 수에 대한 카운터를 업데이트하는 데 사용됩니다.
  • rootBounds: 지정한 루트 요소의 사각형 정보(DOMRectReadOnly)
  • target: IntersectionObserver.observe()를 통해 관찰대상이 된 요소 (Element)
  • time: 교차변경이 발생한 시간 정보(DOMHighResTimeStamp)

reference

https://developer.mozilla.org/ko/docs/Web/API/IntersectionObserver

https://react.vlpt.us/basic/10-useRef.html

https://ko.reactjs.org/docs/hooks-reference.html#useref

profile
모르는것은 그때그때 기록하기
post-custom-banner

0개의 댓글