[TIL] Hooks (2)(useRef, Custom Hooks)

JunSung Choi·2020년 2월 24일
0

React Hooks

목록 보기
2/4

useRef(useFadeIn)

useRef는 함수형 컴포넌트에서 ref를 사용할 수 있게 해준다.
src/useFadeIn.js

const useFadeIn = (duration = 1, delay = 0) => {
  if (typeof duration !== "number" || typeof delay !== "number") {
    return;
  }
  const element = useRef();
  useEffect(() => {
    if (element.current) {
      const { current } = element;
      current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
      current.style.opacity = 1;
    }
  }, []);
  return { ref: element, style: { opacity: 0 } };
};

useFadeIn 이란 커스텀 hooks를 만들어봤다. 이 함수를 사용해 ref를 이용하여 해당 요소의
transition, opacity를 직접 설정할 수 있다.

useBeforeLeave(custom)

src/useBeforeLeave.js

const useBeforeLeave = beforeFunc => {
  if (typeof beforeFunc !== "function") {
    return;
  }

  const handleEvent = event => {
    const { clientY } = event;

    if (clientY <= 0) {
      beforeFunc();
    }
  };

  useEffect(() => {
    document.addEventListener("mouseleave", handleEvent);
    return () => document.removeEventListener("mouseleave", handleEvent);
  }, []);
};

마우스 커서가 페이지 위로 벗어났을 시에 호출할 수 있는 커스텀 hooks를 만들어봤다.
이벤트 핸들러 등록시에는 useEffect 함수 내에서 핸들러를 추가하고, 뒷정리 함수로 반드시 등록한 핸들러를 제거해줘야 한다.

여기서 잠깐! 등록한 이벤트 핸들러는 왜 제거해줘야 좋을까?

  1. 메모리 누수를 피하기 위해
    -> 최신 브라우저에서는 마운트 해제될 때 이벤트 리스너를 제거하지만 이전 브라우저는 X
  2. 컴포넌트간 이벤트 충돌을 피하기 위해
    -> 다른 컴포넌트에서 로드 된 여러 참조를 가질 수 있음
  3. 사이드이펙트를 제거하기 위해

useAxios(custom)

src/useAxios.js

const useAxios = (opts, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    loading: true,
    error: null,
    data: null
  });

  const [trigger, setTrigger] = useState(0);
  if (!opts.url) {
    return;
  }

  const reFetch = () => {
    setState({
      ...state,
      loading: true
    });
    setTrigger(Date.now());
  };

  useEffect(() => {
    axiosInstance(opts)
      .then(data => {
        setState({
          ...state,
          loading: false,
          data
        });
      })
      .catch(error => {
        setState({
          ...state,
          loading: false,
          error
        });
      });
  }, [trigger]);

  return { ...state, reFetch };
};

App.js

const App = () => {
  const { loading, error, data, reFetch } = useAxios({
    url: "https://yts.mx/api/v2/list_movies.json"
  });

  return (
    <div style={{ height: "1000vh" }}>
      <h1>{data && data.status}</h1>
      <h3>{loading && "loading"}</h3>
      <button onClick={reFetch}>다시요청</button>
    </div>
  );
};

export default App;


axios를 사용해 api 요청하며 error, loading status를 다루는 커스텀 hooks를 만들어봤다.
처음 렌더시 loading이 뜨다가 api 요청 성공시 loading이 사라진다. 다시요청을 눌렀을때도 마찬가지.
클래스형 컴포넌트의 componentDidMount 내 또는 api 요청시에 항상 하던 작업과 비슷한 작업이다.
useEffect()의 두번째 인자 dependency에 [] 빈 배열을 넣어주면 처음 렌더시, 언마운트시(뒷정리 함수) 실행하지만 배열 요소를 넣어주면 그것이 변할 때 useEffect가 실행되며 갱신된다. 그 값으로 trigger라는 state를 만들고 Date.now()를 활용해 랜덤한 값이 들어가 갱신되게 했다.

정리

useEffect의 적절한 활용히 중요해 보인다. 이벤트를 등록하면 뒷정리 함수에서 제거하는 부분이 중요하고, 위처럼 trigger라는 state를 dependency로 사용함으로써 원할때 useEffect가 다시 실행되게 할 수 있다.

profile
Frontend Developer

0개의 댓글