커스텀 훅 만들기
커스텀 훅은 React의 내장 훅을 기반으로 만든 재사용 가능한 함수입니다.
이를 통해 컴포넌트 로직을 추상화하고 재사용할 수 있어, 코드의 가독성과 유지보수성을 크게 향상시킬 수 있습니다.
커스텀 훅의 개념과 이점
커스텀 훅은 다음과 같은 이점을 제공합니다.
- 로직 재사용 : 여러 컴포넌트에서 사용되는 공통 로직을 추출하여 재사용할 수 있습니다.
- 관심사 분리 : 복잡한 로직을 별도의 함수로 분리하여 컴포넌트를 더 깔끔하게 유지할 수 있습니다.
- 테스트 용이성 : 분리된 로직은 독립적으로 테스트하기 쉽습니다.
커스텀 훅 생성 방법
커스텀 훅은 'use'로 시작하는 이름의 함수로 만듭니다
이 함수 내부에서 React의 내장 훅을 사용할 수 있습니다.
기본 구조
function useCustomHook(initialValue) {
// 여기서 useState, useEffect 등의 훅 사용
// ...
return // 필요한 값이나 함수 반환
}
실제 사용 사례
1. 폼 관리 훅
폼 상태 관리를 위한 커스텀 훅을 만들어 보겠습니다.
import { useState } from 'react';
function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
const handleChange = (event) => {
const { name, value } = event.target;
setValues(prevValues => ({ ...prevValues, [name]: value }));
};
const resetForm = () => setValues(initialValues);
return { values, handleChange, resetForm };
}
// 사용 예:
function LoginForm() {
const { values, handleChange, resetForm } = useForm({ username: '', password: '' });
const handleSubmit = (event) => {
event.preventDefault();
console.log('Form submitted:', values);
resetForm();
};
return (
<form onSubmit={handleSubmit}>
<input
name="username"
value={values.username}
onChange={handleChange}
/>
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
/>
<button type="submit">Login</button>
</form>
);
}
2. 데이터 페칭 훅
API 호출을 위한 커스텀 훅을 만들어 보겠습니다.
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
const json = await response.json();
setData(json);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
// 사용 예:
function UserProfile({ userId }) {
const { data: user, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{user.name}</div>;
}
3. 윈도우 크기 감지 훅
윈도우 크기 변화를 감지하는 커스텀 훅을 만들어 보겠습니다.
import { useState, useEffect } from 'react';
function useWindowSize() {
const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return size;
}
// 사용 예:
function ResponsiveComponent() {
const { width, height } = useWindowSize();
return (
<div>
The window size is: {width} x {height}
</div>
);
}
훅 Composition
커스텀 훅은 다른 커스텀 훅이나 내장 훅을 조합하여 더 복잡한 로직을 구현할 수 있습니다.
이를 훅 composition이라고 합니다.
예를 들어, 이전에 만든 useFetch
와 useForm
훅을 조합하여 데이터를 가져오고 수정하는 훅을 만들 수 있습니다.
function useUser(userId) {
const { data: user, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
const { values, handleChange, resetForm } = useForm(user || {});
useEffect(() => {
if (user) {
resetForm(user);
}
}, [user]);
return { user: values, loading, error, handleChange };
}
// 사용 예:
function EditUserForm({ userId }) {
const { user, loading, error, handleChange } = useUser(userId);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<form>
<input
name="name"
value={user.name}
onChange={handleChange}
/>
{/* 다른 필드들... */}
</form>
);
}
커스텀 훅 작성 시 주의사항
- 명명 규칙 : 커스텀 훅의 이름은 반드시 'use'로 시작해야 합니다. 이는 React가 해당 함수를 훅으로 인식하고 훅 규칙을 적용하기 위함입니다.
- 훅 규칙 준수 : 커스텀 훅 내부에서도 기본 훅 규칙(최상위에서만 호출, 조건부로 호출하지 않기 등)을 준수해야 합니다.
- 부작용 처리 : useEffect 등을 사용할 때 적절한 정리(cleanup) 함수를 반환하여 메모리 누수를 방지해야 합니다.
- 의존성 배열 주의 : useEffect 등의 훅에서 의존성 배열을 정확히 지정하여 불필요한 재실행을 방지해야 합니다.
- 반환값 일관성 : 훅의 반환값 구조를 일관되게 유지하여 사용자가 예측 가능하게 사용할 수 있도록 합니다.
커스텀 훅은 React 애플리케이션에서 로직을 재사용하고 관심사를 분리하는 강력한 도구입니다.
잘 설계된 커스텀 훅은 코드의 중복을 줄이고, 테스트 용이성을 향상시키며, 전반적인 코드 품질을 개선합니다.
복잡한 상태 로직, 사이드 이펙트 처리, 브라우저 API 사용 등 다양한 시나리오에서 커스텀 훅을 활용할 수 있습니다.
이를 통해 컴포넌트는 더 간결해지고 비즈니스 로직에 집중할 수 있게 되며, 재사용 가능한 로직은 프로젝트 전체에서 쉽게 공유될 수 있습니다.
커스텀 훅을 효과적으로 사용하려면 적절한 추상화 수준을 찾는 것이 중요합니다.
너무 특정한 용도로 만들면 재사용성이 떨어지고, 너무 일반적으로 만들면 사용하기 복잡해질 수 있습니다.
프로젝트의 요구사항과 팀의 코딩 스타일을 고려하여 적절한 균형을 찾는 것이 좋습니다.