커스텀 훅을 사용하면 코드 재사용성을 높이고, 컴포넌트의 로직을 더 깔끔하게 분리할 수 있다.
코드 재사용성: 반복되는 로직을 커스텀 훅으로 분리하여 여러 컴포넌트에서 재사용할 수 있습니다. 이를 통해 코드 중복을 줄이고, 유지보수를 쉽게 할 수 있다.
컴포넌트의 가독성 향상: 데이터 페칭, 상태 관리 등 복잡한 로직을 커스텀 훅으로 분리하여 컴포넌트의 코드가 간결해집니다. 이렇게 하면 컴포넌트는 UI에만 집중할 수 있게 되어 가독성이 높아집니다.
테스트 용이성: 커스텀 훅을 사용하면 비즈니스 로직을 독립적으로 테스트할 수 있습니다. 훅을 별도로 테스트하여 컴포넌트의 의존성을 줄이고, 테스트 코드를 간단하게 유지할 수 있다.
상태와 로직 분리: 커스텀 훅을 사용하면 상태와 로직을 컴포넌트에서 분리하여 관심사의 분리가 명확해집니다. 이를 통해 코드를 더 모듈화하고, 각 부분의 역할을 명확히 할 수 있다.
useExpenses라는 커스텀 훅을 만들어 간단한 지출 목록을 만드려 한다.axios를 사용하여 서버에서 데이터를 가져오고 커스텀 훅을 사용하여 데이터를 컴포넌트에 전달 하는것까지 구현 해보려 한다.
HTTP 요청을 위해 axios를 설치한다.
npm install axios
서버와 통신하기 위해
axios인스턴스를 설정한다. 이를 통해 API 호출을 더 쉽게 할 수 있다.
// src/axios/api.js
import axios from 'axios';
// 기본 URL을 설정합니다.
const api = axios.create({
baseURL: 'http://localhost:5000',
});
export default api;
! 이 훅은 데이터를 가져오고, 로딩 상태와 에러 상태를 관리한다. 이번 글에서 가장 중요한 부분이니, 코드를 세세하게 살펴보자! 🤓
// src/hooks/useExpenses.js
import { useState, useEffect } from 'react';
import api from '../axios/api';
const useExpenses = () => {
const [expenses, setExpenses] = useState([]); // 지출 데이터를 저장할 상태
const [loading, setLoading] = useState(true); // 로딩 상태
const [error, setError] = useState(null); // 에러 상태
useEffect(() => {
const fetchExpenses = async () => {
try {
const response = await api.get('/expenses'); // API 요청
setExpenses(response.data); // 데이터 저장
} catch (err) {
setError(err); // 에러 저장
} finally {
setLoading(false); // 로딩 완료
}
};
fetchExpenses();
}, []);
return { expenses, loading, error }; // 상태 반환
};
export default useExpenses;
const [expenses, setExpenses] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchExpenses = async () => {
try {
const response = await api.get('/expenses'); // 서버에서 데이터 가져오기
setExpenses(response.data); // 가져온 데이터를 상태에 저장
} catch (err) {
setError(err); // 에러가 발생하면 에러 상태에 저장
} finally {
setLoading(false); // 데이터 로딩이 끝나면 로딩 상태를 false로 설정
}
};
fetchExpenses();
}, []);
return { expenses, loading, error };
}
이 훅을 사용해서 지출 데이터를 화면에 보여준다.
// src/components/ExpenseList.js
import React from 'react';
import useExpenses from '../hooks/useExpenses';
const ExpenseList = () => {
const { expenses, loading, error } = useExpenses(); // 커스텀 훅 사용
if (loading) return <p>로딩 중...</p>; // 로딩 중일 때
if (error) return <p>에러가 발생했습니다.</p>; // 에러가 발생했을 때
return (
<ul>
{expenses.map((expense) => (
<li key={expense.id}>
{expense.item}: {expense.amount}원
</li>
))}
</ul>
);
};
export default ExpenseList;
// src/App.js
import React from 'react';
import ExpenseList from './components/ExpenseList';
const App = () => {
return (
<div>
<h1>지출 목록</h1>
<ExpenseList />
</div>
);
};
export default App;
위의 예제는 http://localhost:5000/expenses 엔드포인트를 사용했다. 이를 위해 간단한 JSON 서버를 설정할 수 있다.
npm install -g json-server
db.json파일을 프로젝트 루트에 생성한다. (src)
{
"expenses": [
{ "id": 1, "item": "커피", "amount": 4000 },
{ "id": 2, "item": "샌드위치", "amount": 5500 }
]
}
json-server --watch db.json --port 5000
🤓 이때! package.json에 미리 설정해두면 해당 명령어로 간편하게 서버를 실행 시킬 수 있기때문에 미리 등록 해두는것이 좋다. 등록한 뒤에는 npm run json을 하면 위의 명령어와 동일하게 json 서버를 실행 시킬 수 있다.
// package.json
"scripts": {
...
"json": "json-server --watch src/db.json --port 5000"
},
커스텀 훅을 잘 사용하면 코드의 재사용성을 높이고, 코드가 더 모듈화되어 좋은거 같다. 필요한 부분이 있다면 커스텀 훅을 많이 만들어보는 연습을 해야겠다!