반복되는 로직을 훅으로 뽑아내 재사용하기.
커스텀 훅 만들기
여러 컴포넌트에서 같은 상태 로직이 반복된다면, 그 로직을 커스텀 훅으로 뽑아낼 수 있습니다. 컴포넌트는 깔끔해지고 로직은 한 곳에서 관리됩니다.
학습 목표
- 커스텀 훅으로 로직을 재사용하는 이유를 안다.
use접두사 규칙과 훅의 규칙을 지킬 수 있다.useToggle,useLocalStorage같은 실용 훅을 만들 수 있다.- 커스텀 훅이 state를 공유하지 않는다는 점을 이해한다.
커스텀 훅이란?
커스텀 훅은 그저 use 로 시작하는 일반 함수이며, 내부에서 다른 훅(useState, useEffect 등)을 호출할 수 있습니다. 컴포넌트에서 떼어낸 "재사용 가능한 로직 묶음"입니다.
import { useState } from 'react';
function useCounter(initial = 0) {
const [count, setCount] = useState(initial);
const increment = () => setCount((c) => c + 1);
const decrement = () => setCount((c) => c - 1);
const reset = () => setCount(initial);
return { count, increment, decrement, reset };
}
// 사용
function Counter() {
const { count, increment, reset } = useCounter(0);
return (
<>
<p>{count}</p>
<button onClick={increment}>+1</button>
<button onClick={reset}>리셋</button>
</>
);
}
use 접두사 규칙
이름이 use 로 시작해야 React가 "이건 훅"이라고 인식해 규칙 검사와 린트를 적용합니다.
💡 TIP — 내부에서 훅을 하나도 안 쓰는 그냥 유틸 함수라면
use를 붙이지 마세요. 반대로 훅을 쓴다면 반드시use로 시작하세요.
useToggle 예제
불리언을 켜고 끄는 흔한 패턴입니다.
import { useState, useCallback } from 'react';
function useToggle(initial = false) {
const [on, setOn] = useState(initial);
const toggle = useCallback(() => setOn((v) => !v), []);
return [on, toggle];
}
function Panel() {
const [open, toggleOpen] = useToggle();
return (
<>
<button onClick={toggleOpen}>{open ? '닫기' : '열기'}</button>
{open && <div>패널 내용</div>}
</>
);
}
useLocalStorage 예제
state를 브라우저 localStorage 와 동기화해, 새로고침해도 값이 남게 합니다.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initial) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key);
return saved !== null ? JSON.parse(saved) : initial; // 지연 초기화
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// 사용 — useState와 똑같은 모양!
function Settings() {
const [name, setName] = useLocalStorage('name', '');
return <input value={name} onChange={(e) => setName(e.target.value)} />;
}
- 첫 렌더에서만
localStorage를 읽도록 지연 초기화(함수 형태)를 썼습니다. - 값이 바뀔 때마다 effect가 저장합니다.
훅의 규칙
커스텀 훅이든 내장 훅이든 다음 두 규칙을 반드시 지켜야 합니다.
- 최상위에서만 호출 —
if, 반복문, 중첩 함수 안에서 호출하면 안 됩니다. 호출 순서가 매 렌더 같아야 React가 state를 올바르게 연결합니다. - React 함수 안에서만 호출 — 컴포넌트나 다른 커스텀 훅 안에서만. 일반 함수에서는 안 됩니다.
// ❌ 조건 안에서 훅 호출
if (loggedIn) {
const [x, setX] = useState(0);
}
// ✅ 최상위에서 호출하고, 조건은 안에서
const [x, setX] = useState(0);
if (loggedIn) { /* x 사용 */ }
⚠️ 주의 — 같은 커스텀 훅을 두 컴포넌트가 써도 state는 공유되지 않습니다. 각 컴포넌트가 자기만의 독립된 state를 갖습니다. 상태를 공유하려면 Context나 부모로 끌어올리세요.
요약
- 커스텀 훅 =
use로 시작하고 내부에서 훅을 쓰는 함수. - 반복되는 상태 로직을 뽑아 컴포넌트를 깔끔하게 만든다.
useToggle,useLocalStorage처럼useState와 같은 사용감을 만들 수 있다.- 훅은 최상위에서, React 함수 안에서만 호출한다.
- 커스텀 훅은 로직을 공유할 뿐 state는 공유하지 않는다.
연습문제
- 마우스 위치
{ x, y }를 추적하는useMousePosition훅을 만드세요. (이벤트 구독·해제 포함) useToggle에setTrue,setFalse도 추가해 반환하세요.- 창 너비를 알려주는
useWindowWidth훅을 만들고 리사이즈에 반응하게 하세요. useLocalStorage를 사용해 다크모드 on/off 상태를 새로고침 후에도 유지하세요.
힌트 — 1·3번은
useEffect에서 이벤트 등록 후 클린업으로 해제. 4번은useLocalStorage('dark', false).
💡 연습문제 풀이
불러오는 중…
댓글 0
“React.js” 강좌에 대한 댓글입니다.