의도: 커스텀 훅을 사용할 정도로 코드 퀄리티에 관심이 있는지 파악하려는 질문
나의 답안
네, 저는 커스텀 훅을 적극적으로 사용합니다.
특히 당장 여러 곳에서 재사용하지 않더라도, 재사용 가능성이 높고 UI와 분리되어야 하는 비즈니스 로직은 선제적으로 커스텀 훅으로 빼둡니다.
이렇게 해두면 코드 구조가 명확해지고, 이후 기능 확장이나 화면 추가 시 동일한 패턴으로 손쉽게 재사용할 수 있습니다.저는 API 데이터 요청, 모달 상태 관리, 폼 입력 검증, 무한 스크롤 감지 등의 로직을 커스텀 훅으로 분리해서 사용했습니다.
그 중 하나의 예를 구체적으로 말씀드리자면, 영어 일기 서비스를 구현하는 과정에서 전체 일기 데이터를 무한 스크롤로 불러오는 로직을 단일 커스텀 훅으로 추상화했습니다.
이로 인해 각 화면은 페이지네이션 구현 세부사항을 몰라도 동일한 인터페이스로 데이터를 소비할 수 있습니다.
staleTime 조정, 에러/리트라이 전략과 같은 정책 변경도 훅 한 곳에서 일괄 관리가 가능해 유지보수성이 크게 향상됐습니다.
주어진 답안 (모범 답안)
네. 저는 최근 프로젝트에서 커스텀 훅을 사용한 경험이 있습니다.
개인적으로도 정말 잘 사용하고 있는 기술이기도 합니다.커스텀 훅을 사용한다면 기존의 컴포넌트 내부에 작성된 코드를 커스텀 훅을 만들어 정리하는 것으로 컴포넌트 내부를 좀 더 클린하게 정리할 수 있을 뿐더러 만들어진 커스텀 훅을 좀 더 보편적으로 개선하여 다른 컴포넌트에서도 재사용할 수 있습니다.
또한 비즈니스 로직의 분리를 실현하여 의존성을 줄이고 유지 보수성을 높일 수 있는 등 다양한 장점이 많습니다.사소한 단점으로는 커스텀 훅의 이름을 잘 지어줘야 다른 개발자들이 굳이 커스텀 훅의 내부를 들여다 보는 수고를 하지 않을 수 있다는 점이 있습니다.
어찌보면 선언형 코드와 장단점을 공유하는 듯 합니다.저 같은 경우에는
useLocalStorage훅을 작성하여 기존에 로컬 스토리지에 저장하고 읽어올 때 반복되는 로직을 통합하여 재사용성을 목적으로 구현한 바 있습니다.
기존에는JSON.parse나JSON.stringify같은 메서드를 매번 호출해서 읽고, 저장해야 했지만 이 커스텀 훅을 구현함으로써 기존의useState와 같은 사용감을 만들어 냈습니다.
useState, useEffect, useContext 등)을 사용하여 반복되는 로직을 재사용 가능한 함수로 추출한 것이다.use로 시작해야 한다.React 컴포넌트를 작성하다 보면 여러 컴포넌트에서 동일한 로직이 반복될 때가 있다.
예를 들어, API 데이터를 가져오는 로직이나 폼 처리 로직이 여러 컴포넌트에서 사용된다면, 이를 별도로 분리해서 재사용 가능한 방식으로 관리할 수 있다.
이런 상황에서 커스텀 훅을 사용하면 상태 및 사이드 이펙트 로직을 깔끔하게 분리할 수 있다.
use로 시작한다.예제 1: 윈도우 크기 추적 커스텀 훅
import { useState, useEffect } from "react";
// 윈도우 크기 추적을 위한 커스텀 훅
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
// 윈도우 리사이즈 이벤트 리스너 추가
window.addEventListener("resize", handleResize);
// 컴포넌트 언마운트 시 이벤트 리스너 제거
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return windowSize;
}
export default useWindowSize;
사용 예시
import React from "react";
import useWindowSize from "./useWindowSize";
function App() {
const { width, height } = useWindowSize();
return (
<div>
<h1>윈도우 크기</h1>
<p>가로: {width}px</p>
<p>세로: {height}px</p>
</div>
);
}
export default App;
예제 2: API 호출 커스텀 훅
import { useState, useEffect } from "react";
import axios from "axios";
// 데이터 가져오기 훅
function useFetch(url: string) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get(url);
setData(response.data);
} catch (err) {
setError("데이터를 가져오는 중 문제가 발생했습니다.");
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
사용 예시
import React from "react";
import useFetch from "./useFetch";
function UsersList() {
const { data, loading, error } = useFetch("https://jsonplaceholder.typicode.com/users");
if (loading) return <p>로딩 중...</p>;
if (error) return <p>{error}</p>;
return (
<div>
<h1>유저 목록</h1>
<ul>
{data?.map((user: any) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
export default UsersList;
로직 재사용성
여러 컴포넌트에서 동일한 로직을 반복할 필요 없이 커스텀 훅으로 추출해 재사용할 수 있다.
컴포넌트 단순화
복잡한 상태 관리 및 사이드 이펙트 로직을 컴포넌트에서 분리하여 코드의 가독성과 유지보수성을 높인다.
테스트 용이성
상태와 사이드 이펙트 로직이 캡슐화되므로, 테스트를 별도로 작성하기 쉽다.
추상화 제공
특정 기능(예: API 호출, 폼 상태 관리)을 커스텀 훅으로 캡슐화하면, 컴포넌트는 그 훅의 인터페이스만 신경 쓰면 된다.
훅 규칙을 준수해야 한다.
use로 시작해야 한다.종속성 배열 관리
훅 내부에서 useEffect를 사용하는 경우, 종속성 배열을 올바르게 관리해야 의도하지 않은 동작을 방지할 수 있다.
UI와 로직 분리
커스텀 훅은 오직 상태 및 로직만 관리해야 하며, JSX와 같은 UI 코드는 포함하지 않는 것이 좋다.