TIL27. 리액트 custom hook 연습하기

imloopy·2022년 5월 29일
0

Today I Learned

목록 보기
30/56

다분히 TIL 스러운 글입니다

오늘 공부한 것

  • custom hook 만드는 연습하기
    • useInput
    • useHover
    • useKeyPress
    • useToggle
  • 컴포넌트와 로직 분리하기
    • useIntersect

느낀 점

기존에 실무에서 사용할 수 있는 custom hook 만드는 강의를 들었는데, 역시 코드를 그냥 따라 치는 것과 스스로 코드를 작성하는 것은 매우 다름을 느꼈다. 그때는 할 만하다고 느꼈던 custom hook 만들기가 이렇게 어려웠을 줄이야… 다시 한 번 느끼는 복습의 중요성

hook은 functional component의 장점을 극대화 시킬 수 있는 좋은 패러다임같다. 클래스 컴포넌트를 사용해 본 적은 없지만, 클래스 컴포넌트는 로직과 컴포넌트의 분리가 어렵다고 들었다. 한 번 만들어 둔 로직을 재사용할 수 있다는 사실은 생산성에 있어 중요한 요소이다. 다만, 어디부터 어디까지를 분리해야 할 지 구별하는 능력은 아직 부족한 것 같아, 컴포넌트를 만들 때 이 부분의 로직을 분리하여 재사용할 수 있는가?를 생각하면서 작성해야겠다.

사실 그래도 위 4개의 커스텀 훅을 만드는 과정은 생각보다 어렵지는 않았는데(물론 몇 몇 커스텀 훅들은 useEffect로 사이드 이펙트를 관리한다는 점에서 다소 생각의 흐름 따라가기가 어렵긴 했지만) 기존의 코드에서 useIntersect hook으로 분리하는 과정이 많이 어려웠다..

  • Intersection Observer에 대한 이해가 부족
  • 기존의 코드가 재사용성에 대한 염두를 하지 않고 작성을 했기 때문에 분리 포인트가 확실하게 드러나지 않음

앞으로 해야할 일

  • Intersection Observer에 대하여 좀 더 공부하기
  • 공통되는 부분을 찾아서 정리하는 훈련 하기, 항상 재사용을 염두해두고 코드를 작성하기(모듈화가 가능하도록)

useIntersect

lazy loading 뿐만 아니라, 스켈레톤, 무한 스크롤 등 다양한 곳에서 intersection observer의 개념이 사용되기 때문에 이번 기회에 useIntersect라는 hook을 만들어보자고 결심했다.

IntersectionObserver

Intersection Observer는 observing 하는 물체가 화면에 들어왔는지를 관찰하여 들어왔다면, 콜백함수를 실행하는 api이다.

  1. observer가 없다면 observer를 등록
  2. observer가 관찰될 때 실행할 콜백함수를 만듬
  3. 컴포넌트가 더 이상 존재하지 않거나, deps가 바뀔 경우를 대비하여 disconnect 함수 등록

리액트에서 모든 사이드 이펙트(라이프사이클과 무관한 작업, 또는 함수형 컴포넌트 밖에서 로컬의 상태를 변경하는 작업)는 useEffect hook에서 관리하기 때문에 useEffect hook에서 Intersection Observer를 관리한다.

useEffect(() => {
    let observer: null | IntersectionObserver = null;
    if (ref.current) {
      observer = new IntersectionObserver(checkIntersect, { threshold });
      observer.observe(ref.current);
    }
    return () => observer?.disconnect();
  }, [checkIntersect, threshold]);

그리고 checkIntersect라는 콜백함수를 useCallback으로 만들어주었다. 같은 프롭이더라도 재렌더링이 되는 것을 방지하기 위함이다.

const checkIntersect: IntersectionObserverCallback = useCallback(
    ([entry], observer) => {
      if (entry.isIntersecting) {
        onIntersect(entry, observer);
      }
    },
    [onIntersect],
  );

대부분의 다른 블로그들을 보면 useState로 ref를 관리하고 있는데, 타입 스크립트에서 타입 에러가 발생하기 때문에 useRef로 그냥 관리하였다. 간단히 테스트 해보았는데 아직 문제점은 발견하지 못했다. 이 부분은 좀 더 알아볼 필요가 있다.

전체 코드

import React, { useRef, useEffect, useCallback } from 'react';

const useIntersect = <T extends Element = Element>(
  onIntersect: (
    entry: IntersectionObserverEntry,
    observer: IntersectionObserver,
  ) => void,
  threshold = 0,
): React.RefObject<T> => {
  const ref = useRef<T>(null);
  const checkIntersect: IntersectionObserverCallback = useCallback(
    ([entry], observer) => {
      if (entry.isIntersecting) {
        onIntersect(entry, observer);
      }
    },
    [onIntersect],
  );

  useEffect(() => {
    let observer: null | IntersectionObserver = null;
    if (ref.current) {
      observer = new IntersectionObserver(checkIntersect, { threshold });
      observer.observe(ref.current);
    }
    return () => observer?.disconnect();
  }, [checkIntersect, threshold]);

  return ref;
};

export default useIntersect;

출처

intersection observer에 대해 알아보기

0개의 댓글