본문 바로가기
개발

훅과 유틸... hook util의 차이를 아는가

by mlheein 2026. 1. 21.

"리액트 엔진을 사용하느냐 아니냐"

1. util 폴더: "리액트 따위(?) 몰라도 돼" (Pure JS)

util 폴더에 들어가는 함수들은 리액트라는 환경에 전혀 의존하지 않는 '순수 자바스크립트/타입스크립트' 로직입니다.

  • 특징: 어떤 환경(Node.js, 바닐라 JS, React)에서도 그대로 가져다 쓸 수 있습니다.
  • 예시: 날짜 포맷팅(2024-05-20 → 2024년 5월 20일), 숫자 세 자릿수 콤마 찍기, 복잡한 수학 계산 등.
  • 테스트: 리액트 컴포넌트를 렌더링할 필요 없이 함수만 불러와서 테스트하면 되니 매우 빠르고 쉽습니다.
// 이건 순수 JS 로직이므로 util 폴더에 어울립니다.
export const convertToUpper = (str: string) => str.toUpperCase();

2. hook 폴더: "난 리액트 없으면 못 살아" (React-Dependent)

hook 폴더에 들어가는 함수들은 리액트의 심장 박동(Lifecycle)과 상태 관리 시스템에 연결된 로직입니다.

  • 특징: 내부에서 useState, useEffect, useContext 혹은 useQuery(TanStack Query) 같은 리액트 전용 기능을 하나라도 사용합니다.
  • 예시: useAuth(로그인 상태 체크), useGetReport(API 데이터 가져오기), useWindowSize(화면 크기 감지).
  • 테스트: 반드시 리액트 환경을 꾸며주는 도구(@testing-library/react-hooks 등)가 있어야 테스트가 가능합니다.
// src/hooks/useUpperTitle.ts
import { useEffect, useState } from 'react';
import { convertToUpper } from '@/utils/stringUtils'; // util 사용

export const useUpperTitle = (title: string) => {
  const [upper, setUpper] = useState('');

  useEffect(() => {
    // 리액트의 생명주기(useEffect) 안에서 문자열 처리를 수행
    const result = convertToUpper(title); 
    setUpper(result);
  }, [title]); // title이 바뀔 때만 리액트가 알아서 실행해줘!

  return upper;
};

API를 호출할 때:

  • 단순히 axios.get(...)만 하고 끝나는 순수 통신 로직이라면? → api/ 또는 util/
  • useQuery나 useEffect를 써서 그 결과를 리액트 상태나 캐시에 담는 로직이라면? → hook/

 

이전 글이랑 이어지는 상황 : 

api에서 util은 되고 hook은 안된다.

  • util -> api (환상의 짝꿍): api 폴더에서 데이터를 받아온 뒤, 그 데이터를 가공하기 위해 util에 있는 문자열 처리 함수를 쓰는 것은 매우 자연스러운 흐름입니다. 둘 다 리액트 엔진 없이도 돌아가는 '자유로운 영혼'들이기 때문이죠.
  • hook -> api (금기된 조합): 앞서 공부했듯이, hook은 실행되는 순간 "나 지금 리액트 컴포넌트 안에서 실행 중인가?"를 체크합니다. api 폴더의 일반 함수는 리액트 컴포넌트가 아니므로, 여기서 훅을 부르는 순간 리액트가 "경찰(Error)"을 부릅니다.