← 홈페이지 5강 목록으로
🪝
EPISODE 05
use* · useFetch · useLocalStorage · useDebounce

커스텀 훅 (Custom Hook)

use로 시작하는 커스텀 훅의 개념과 ESLint 규칙, 공통 로직 추출의 이점, 그리고 useFetch/useLocalStorage/useDebounce 직접 구현을 다룹니다.

Reactcustom hookuseFetch
소요 시간
45분
난이도
📊 중급
선수 조건
🎯 react-04
결과물
재사용 가능한 useFetch/useLocalStorage/useDebounce

이 강의에서 배우는 것

  • 1커스텀 훅이 use로 시작해야 하는 이유를 안다
  • 2중복 로직을 커스텀 훅으로 추출한다
  • 3useFetch — Promise/AbortController 패턴을 적용한다
  • 4useLocalStorage — JSON 직렬화·복원을 처리한다
  • 5useDebounce — setTimeout/clearTimeout 패턴을 안다

1. 커스텀 훅이란

jsx
// ✅ use로 시작
function useWindowSize() { ... }
function useFetch(url) { ... }

// ❌ use로 시작하지 않으면 훅 규칙 검사 X
function getWindowSize() { ... }
  • React는 use로 시작하는 함수에서만 훅 규칙 검사
  • ESLint react-hooks/rules-of-hooks가 정상 동작
  • 다른 개발자가 즉시 훅임을 인식

2. 로직 추출의 이점

추출 전 — 중복

jsx
function ComponentA() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  // ... 같은 패턴 반복
}

추출 후 — 한 줄로 해결

jsx
function ComponentA() {
  const { data, isLoading, error } = useFetch('/api/users');
}

function ComponentB() {
  const { data, isLoading, error } = useFetch('/api/products');
}

3. useFetch

jsx
function useFetch(url) {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (!url) return;
    const controller = new AbortController();
    setIsLoading(true);

    fetch(url, { signal: controller.signal })
      .then(r => { if (!r.ok) throw new Error('실패'); return r.json(); })
      .then(setData)
      .catch(err => { if (err.name !== 'AbortError') setError(err.message); })
      .finally(() => setIsLoading(false));

    return () => controller.abort();
  }, [url]);

  return { data, isLoading, error };
}

4. useLocalStorage

jsx
function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch {
      return initialValue;
    }
  });

  const setValue = (value) => {
    const valueToStore = value instanceof Function ? value(storedValue) : value;
    setStoredValue(valueToStore);
    localStorage.setItem(key, JSON.stringify(valueToStore));
  };

  return [storedValue, setValue];
}

5. useDebounce

jsx
function useDebounce(value, delay = 500) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
}
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗