Custom Hook이란?
useState()
와 같은 내장된 Hook(정규 함수)과 동일하다. 다만, 내부 상태를 설정할 수 있는 로직이 포함된 것 뿐이다.
custom hook은 재사용 가능한 함수에 상태를 설정하는 로직을 outsourcing할 수 있는 장점이 있다.
다시 말해, 정규 함수와는 다르게 custom hook은 다른 custom hook을 포함한 다른 react hook들을 사용할 수 있다.
useState()
나
useReducer()
를 통해 관리하는 React state를 활용할 수 있다는 말이다.
이를 통해 다양한 component에서 호출이 가능해지며, 로직 재사용이 가능한 매카니즘이다.
주로, 코드가 중복되는 경우 re-factoring과 함수의 재사용을 위해서 이용된다.
일반적인 경우, 위의 사진과 같은 경로에 배치를 하며, 반드시 함수의 이름은 use로 시작해야한다.
use
로 시작하는 함수는 React에게 custom hook임을 알려주며, React가 해당 함수를 hook의 규칙에 따라서 사용하겠다고 보장한다.
즉, 해당 custom hook을 내장 hook과 동일한 방식으로 사용하겠다는 것을 의미한다.
이는 React가 요구하는 것으로, 만약 그렇지 않는다면 문제가 발생한다.
예를 들어, 내장 hook을 사용하는 custom hook을 잘못된 곳에 사용한다면, 내장 hook 또한 잘못된 곳에서 사용됨을 내포한다.
이렇게 use
라는 함수 이름으로 시작해야 React가 hook의 규칙을 위반했을 때, 경고를 보낼 수 있다.
예제 코드
다음 예제는 페이지가 로드된 이후에 1000ms마다 숫자가 1증가하고 감소하는 화면이다.
이 페이지에 있는 두개의 component[ForwardCounter()
, BackwardCounter()
]의 중복적인 코드를 custom hook으로 바꾸는 과정이다.
// 📂 In ForwardCounter component
import { useState, useEffect } from 'react';
import Card from './Card';
const ForwardCounter = () => {
const [counter, setCounter] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCounter((prevCounter) => prevCounter + 1);✨
}, 1000);
return () => clearInterval(interval);
}, []);
return <Card>{counter}</Card>;
};
export default ForwardCounter;
// 📂 In BackwardCounter component
import { useState, useEffect } from 'react';
import Card from './Card';
const BackwardCounter = () => {
const [counter, setCounter] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCounter((prevCounter) => prevCounter - 1);✨
}, 1000);
return () => clearInterval(interval);
}, []);
return <Card>{counter}</Card>;
};
export default BackwardCounter;
위의 코드를 아래 파일로 re-factoring 했다.
// 📂 In ForwardCounter component using useCounter custom hook
import useCounter from '../hooks/useCounter';
import Card from './Card';
const ForwardCounter = () => {
const counter = useCounter() ;
return <Card>{counter}</Card>;
};
export default ForwardCounter;
// 📂 In BackwardCounter component using useCounter custom hook
import useCounter from '../hooks/useCounter';
import Card from './Card';
const BackwardCounter = () => {
const counter = useCounter(false) ;
return <Card>{counter}</Card>;
};
export default BackwardCounter;
// 📂 In useCounter custom Hook
import React, { useState, useEffect } from "react";
const useCounter = (forwards = true) => {
const [counter, setCounter] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCounter((prevCounter) => prevCounter + (forwards ? 1 : -1));
}, 1000);
return () => clearInterval(interval);
}, []);
return counter ;
};
export default useCounter;
다수의 component에서 custom hook을 사용하면 각각의 state를 받게 될 것이다.
custom hook을 사용한다고 해서 component 전반에 걸쳐 state를 공유한다는 개념이 아니다.
따라서 예제에서 useCounter()
를 호출한 ForwardCounter()
component에 의해서 state가 설정될 것이다.
내장 hook을 사용할 때와 마찬가지로 custom hook에서는 무언가를 return
하는데 그 무언가는 어떠한 것이든 가능하다.
해당 예제에서는 state 값을return
해주었으며, parameter로 forwards
를 받아 parameter에 따라 재사용가능하도록 구성했다.
물론, 조금 더 유연성있게 코드하기 위해서는 prarameter로 함수의 pointer를 전달하면 가능하다.