React 커스텀 훅 : useYScroll

hwisaac·2023년 2월 22일
0

커스텀훅

목록 보기
3/3
post-custom-banner

React에서 특정 컴포넌트의 y-scroll 값을 알려주는 custom hook

import { useState, useEffect } from 'react';

function useYScroll(ref) {
  const [yScroll, setYScroll] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      const { scrollTop } = ref.current;
      setYScroll(scrollTop);
    };

    ref.current.addEventListener('scroll', handleScroll);

    return () => {
      ref.current.removeEventListener('scroll', handleScroll);
    };
  }, [ref]);

  return yScroll;
}

이 hook은 useRef로 참조한 DOM 엘리먼트의 y-scroll 값을 추적합니다. useYScroll을 사용하려면 해당 컴포넌트에서 useRef를 사용하여 해당 DOM 엘리먼트에 대한 참조를 만들고 useYScroll을 호출하여 y-scroll 값을 가져올 수 있습니다.

예를 들어, 다음과 같이 사용할 수 있습니다.

import { useRef } from 'react';
import useYScroll from './useYScroll';

function MyComponent() {
  const ref = useRef(null);
  const yScroll = useYScroll(ref);

  return (
    <div ref={ref} style={{ height: '200px', overflowY: 'scroll' }}>
      <p>y-scroll value: {yScroll}</p>
    </div>
  );
}

y-scroll 의 값을 0부터 1사이의 값으로 반환하는 경우

다음은 React에서 특정 컴포넌트의 y-scroll 값을 0부터 1 사이의 값으로 반환해주는 custom hook입니다.

import { useState, useEffect } from 'react';

function useYScroll(ref) {
  const [yScroll, setYScroll] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      const { scrollTop, scrollHeight, clientHeight } = ref.current;
      const scrollRatio = scrollTop / (scrollHeight - clientHeight);
      setYScroll(scrollRatio);
    };

    ref.current.addEventListener('scroll', handleScroll);

    return () => {
      ref.current.removeEventListener('scroll', handleScroll);
    };
  }, [ref]);

  return yScroll;
}

이 hook은 useRef로 참조한 DOM 엘리먼트의 y-scroll 값을 추적합니다. useYScroll을 사용하려면 해당 컴포넌트에서 useRef를 사용하여 해당 DOM 엘리먼트에 대한 참조를 만들고 useYScroll을 호출하여 0부터 1 사이의 y-scroll 값을 가져올 수 있습니다.

이 훅의 문제점과 개선

  1. 현재 구현에서는 스크롤 이벤트가 발생할 때마다 y-scroll 값을 업데이트합니다. 하지만 스크롤 이벤트는 매우 자주 발생하므로 불필요한 렌더링을 유발할 수 있습니다. 이를 개선하기 위해서는 스크롤 이벤트를 일정 주기로 쓰로틀링하거나 디바운싱해야 합니다.
  2. 현재 구현에서는 useEffect에서 의존성 배열로 ref를 사용합니다. 이는 매번 렌더링될 때마다 useEffect가 호출되어 스크롤 이벤트를 추가하고 제거하므로 성능상 이슈가 될 수 있습니다. 이를 개선하기 위해서는 useMemo를 사용하여 의존성 배열을 최적화할 수 있습니다.

useMemo 를 사용하기

import { useState, useEffect, useMemo } from 'react';

function useYScroll(ref) {
  const [yScroll, setYScroll] = useState(0);

  const handleScroll = useMemo(() => {
    return () => {
      const { scrollTop, scrollHeight, clientHeight } = ref.current;
      const scrollRatio = scrollTop / (scrollHeight - clientHeight);
      setYScroll(scrollRatio);
    };
  }, [ref]);

  useEffect(() => {
    ref.current.addEventListener('scroll', handleScroll);

    return () => {
      ref.current.removeEventListener('scroll', handleScroll);
    };
  }, [ref, handleScroll]);

  return yScroll;
}

여기서는 handleScroll 함수를 useMemo를 사용하여 캐싱합니다. 이제 의존성 배열을 최적화하면 handleScroll 함수가 변경될 때마다 useEffect가 호출되는 것을 방지할 수 있습니다.

throttle 사용하기

쓰로틀링(throttling)이나 디바운싱(debouncing)을 적용하려면 Lodash와 같은 라이브러리에서 제공하는 함수를 사용하거나, 직접 함수를 작성할 수 있습니다. 여기서는 Lodash의 throttle 함수를 사용하여 useYScroll 훅을 개선하는 방법을 알아보겠습니다.

import { useState, useEffect, useMemo } from 'react';
import { throttle } from 'lodash';

function useYScroll(ref, wait = 100) {
  const [yScroll, setYScroll] = useState(0);

  const handleScroll = useMemo(() => {
    return throttle(() => {
      const { scrollTop, scrollHeight, clientHeight } = ref.current;
      const scrollRatio = scrollTop / (scrollHeight - clientHeight);
      setYScroll(scrollRatio);
    }, wait);
  }, [ref, wait]);

  useEffect(() => {
    ref.current.addEventListener('scroll', handleScroll);

    return () => {
      ref.current.removeEventListener('scroll', handleScroll);
      handleScroll.cancel();
    };
  }, [ref, handleScroll]);

  return yScroll;
}

여기서는 Lodash에서 제공하는 throttle 함수를 사용하여 handleScroll 함수를 일정 시간(wait)마다 한 번씩 호출하도록 설정했습니다. handleScroll 함수가 매번 호출되지 않으므로 불필요한 렌더링을 방지할 수 있습니다.

handleScroll 함수를 이전에 사용한 useMemo 함수 안에 감싸서 함수가 매번 새로 생성되는 것을 방지하고 의존성 배열에 wait 값을 추가했습니다.

마지막으로, useEffect 함수에서 removeEventListener를 호출할 때 handleScroll 함수를 cancel 해줌으로써 throttle 함수가 비활성화되도록 처리했습니다.

이제 useYScroll 훅은 스크롤 이벤트가 매우 자주 발생할 때도 성능적으로 안정적으로 동작할 수 있게 되었습니다.

post-custom-banner

0개의 댓글