커스텀 훅(Custom Hook)이란?
리액트의 내장 훅(useState, useEffect, 등)을 활용해
자주 쓰이는 로직을 함수처럼 재사용할 수 있도록 만든 사용자 정의 훅을 말합니다.
// 이름은 반드시 use로 시작해야 함
function useSomething() {
// 내부에서 다른 훅 사용 가능
return ...;
}
왜 커스텀 훅을 사용할까?
1. 로직의 재사용
- 같은 useState, onChange 로직을 매번 반복해서 작성하는 건 비효율적 입니다.
- 훅으로 빼서 함수처럼 가져다 쓰면 됩니다.
2. 컴포넌트 간 중복 제거
- 예: 폼 입력 관리, 로딩/에러 처리, fetch 요청 등
3. UI가 아닌 로직만 다룬다 (로직 추출 전용)
- UI 컴포넌트와 로직이 분리되어 코드 가독성/테스트성 향상됩니다.
4. 각 컴포넌트마다 상태는 독립적으로 관리됨
- 커스텀 훅을 여러 곳에서 써도, 각자 state를 가집니다. (전역 상태 아님!)
대표예시
// src/hooks/useInput.js
import { useState } from "react";
function useInput(initialValue = "") {
const [value, setValue] = useState(initialValue);
const handleChange = (e) => {
setValue(e.target.value);
};
return [value, handleChange];
}
export default useInput;
중복되는 코드들을 내장 훅을 사용해서 커스텀 훅으로 만든 후 리턴값으로 반환
import useInput from "../hooks/useInput";
function LoginForm() {
const [email, onChangeEmail] = useInput();
const [password, onChangePassword] = useInput();
return (
<form>
<input value={email} onChange={onChangeEmail} />
<input value={password} onChange={onChangePassword} />
</form>
);
}
커스텀 훅으로 만들어 보면 좋은 상황들
- ✅ 인풋 상태 관리 (useInput)
- ✅ 토글 열고 닫기 (useToggle)
- ✅ 타이머 (useInterval)
- ✅ 브라우저 사이즈 감지 (useWindowSize)
- ✅ 스크롤 위치 추적 (useScroll)
- ✅ API 호출 (useFetch)
- ✅ 외부 이벤트 감지 (useOutsideClick)
커스텀 훅 가이드
1. 우선 반복되는 로직이 있는지 살펴봅니다.
이걸 매번 컴포넌트에서 다시 작성할 필요 있을까?" 를 계속 고민하면 좋습니다.
예를 들어 폼을 작성할 때 매번 이런 코드가 반복된다고 해보겠습니다.
function LoginForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const onChangeEmail = (e) => setEmail(e.target.value);
const onChangePassword = (e) => setPassword(e.target.value);
return (
<form>
<input value={email} onChange={onChangeEmail} />
<input value={password} onChange={onChangePassword} />
</form>
);
}
2. 재사용 단위로 추출하기
그 로직의 입출력을 정리해보면 어떤 값을 받아서 어떤 값을 반환해야 컴포넌트가 사용하기 편할지 감을 잡을 수 있습니다.
function useInput(initialValue = "") {
const [value, setValue] = useState(initialValue);
const handleChange = (e) => setValue(e.target.value);
return [value, handleChange];
}
3. 훅으로 분리하기
- 훅은 반드시 컴포넌트 최상단에서 호출
- 호출 순서는 항상 동일해야 함
- 훅 이름은 반드시 use로 시작
import { useState } from "react";
function useInput(initialValue = "") {
const [value, setValue] = useState(initialValue);
const handleChange = (e) => {
setValue(e.target.value);
};
return [value, handleChange];
}
export default useInput;
4. 실제 코드에서 사용해보기
훅을 분리해서 훨씬 가독성있고 중복코드 없이 사용할 수 있습니다.
import useInput from "./hooks/useInput";
function LoginForm() {
const [email, onChangeEmail] = useInput();
const [password, onChangePassword] = useInput();
return (
<form>
<input value={email} onChange={onChangeEmail} />
<input value={password} onChange={onChangePassword} />
</form>
);
}
*요약
반복되는 상태 관리 → 입출력 정리 → 훅으로 분리 → 내부에서 훅 조합 → 독립적으로 사용하기
'기술 > React.js' 카테고리의 다른 글
React의 렌더링과 리렌더링 흐름 (2) | 2025.06.22 |
---|---|
React가 빠른 이유: Virtual DOM, Diffing, Reconciliation, Batch Update 이해하기 (0) | 2025.06.18 |
리액트의 특징에 대해 알아보자 (2) | 2025.06.18 |
[문서] 리액트 공식문서 톱아보기: 컴포넌트를 순수하게 유지하자 (1) | 2025.05.06 |
[문서] 리액트 공식문서 톱아보기: 컴포넌트 import 및 export (1) | 2024.11.16 |