본문 바로가기
REACT

커스텀 훅(Custom Hook)

by 일태찡 2023. 2. 16.

 

  • 정규 함수 외에 안에 상태를 설정할 수 있는 로직을 포함한 함수를 의미합니다.
  • 이는 로직 재사용이 가능한 메커니즘을 만드는 것이며 여러 컴퍼넌트에 뿌려도 로직은 공유하지만 상태를 공유하지는 않습니다.
  • 지금까지 어떤 액체를 얼릴 때마다 트레이를 새로 만들었습니다. 하지만 커스텀 훅을 만드는 것은 하나의 얼음 트레이를 만들어 한 컴퍼넌트에선 물을 얼리고 다른 컴퍼넌트에선 오렌지 주스를 얼리는 방식과 비슷합니다.

 

 

초당 숫자가 1씩 올라가는 컴퍼넌트와 초당 숫자가 1씩 내려가는 컴퍼넌트를 만들고 생각해 봅시다.

 

ForwardCounter.js

import { useState, useEffect } from "react";

const ForwardCounter = () => {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCounter((prevCounter) => prevCounter + 1);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return <div>{counter}</div>;
};

export default ForwardCounter;

 

BackwardCounter.js

import { useState, useEffect } from "react";

const BackwardCounter = () => {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCounter((prevCounter) => prevCounter - 1);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return <div>{counter}</div>;
};

export default BackwardCounter;

 

이 둘은 덧셈과 뺄셈 외에는 정확히 동일한 코드이며 이렇게 코드가 중복될 때는 이 코드를 떼어내고 리팩토링을 해야 합니다.

그러기 위해선 공통되는 코드를 갖는 함수를 만들고 각 컴퍼넌트에 뿌려주면 됩니다.

 

 

커스텀 훅 만들기

 

함수 이름 시작에 use가 붙여 리액트에게 이 함수가 커스텀 훅임을 알려주며 이는 리액트가 해당 함수를 훅의 규칙에 따라 사용하겠다고 보장해 주는 것입니다.

즉, 이 커스텀 훅을 내장 훅과 같은 방식으로 쓰겠다는 것 알리는 것입니다.

또, 상태와 관련된 로직을 사용한다던가(useState) 다른 리액트 훅을 사용할 수 있으며(useEffect,...) 이를 통해 컴퍼넌트 간에 특정 로직을 공유할 수 있게 됩니다.

 

use-counter.js

import { useState, useEffect } from "react";

const useCounter = () => {
    const [counter, setCounter] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => {
            setCounter((prevCounter) => prevCounter + 1);
        }, 1000);

        return () => clearInterval(interval);
    }, []);

    // 커스텀 훅에서는 필요한 무엇이든간에 반환이 가능하다
    // return 26, return [], return {}, ...
    // 여기서는 counter가 갖고 있는 숫자를 반환한다
    return counter;
};

export default useCounter;

 

이렇게 커스텀 훅을 구성하면

 

ForwardCounter.js

import useCounter from './use-counter';

const ForwardCounter = () => {
    // useCounter를 통해 저장된 숫자를 counter에 저장해줌
    const counter = useCounter();

    return <div>{counter}</div>;
};

export default ForwardCounter;

 

숫자가 더해지는 컴퍼넌트의 코드가 이렇게 심플해질 수 있습니다.

 

하지만 위의 코드는 사실 정적인 틀이었습니다. 모든 얼음 트레이에 물만 부울 수 있는 것입니다.

많이 이상하죠...? 그럼 우리는 유연하게 훅을 구성하려면 어떻게 해야 할까요??

그건 바로 인자를 구성하고 활용해 주면 되는 겁니다.

 

use-counter.js

import { useState, useEffect } from "react";

const useCounter = (counterUpdateFn) => {
    const [counter, setCounter] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => {
            setCounter(counterUpdateFn());
        }, 1000);

        return () => clearInterval(interval);
    }, []);

    return counter;
};

export default useCounter;

 

이렇게 인자에 함수 자체를 받아와 연결할 수도 있습니다.

또, 위의 예시와 같은 상황을 해결해 보자면

 

use-counter.js

import { useState, useEffect } from "react";

const useCounter = (plus = true) => {
    const [counter, setCounter] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => {
            if (plus) {
                setCounter((prevCounter) => prevCounter + 1);
            } else {
                setCounter((prevCounter) => prevCounter - 1);
            }
        }, 1000);

        return () => clearInterval(interval);
    }, [plus]); // 외부 상태에 의존성이 생겼으므로 추가합니다 !

    return counter;
};

export default useCounter;

 

이렇게 인자를 조건으로 받아 세분화하는 방법도 있습니다.

 

지금까지는 커스텀 훅의 이해를 돕기 위한 너무나 비실용적인 간단한 예시였습니다.

좀 더 현실적인 상황에서의 커스텀 훅은 다음 블로그에 도전해 보겠습니다...

 

 

 

 

 

'REACT' 카테고리의 다른 글

useContext 훅  (5) 2023.03.03
useReducer 훅  (5) 2023.03.02
커스텀 훅으로 HTTP 요청 리팩토링  (8) 2023.02.17
리액트 최적화 테크닉  (7) 2023.02.14
HTTP 요청 보내기  (8) 2023.02.13