React에서 Custom Hook을 활용한 데이터 Fetching과 최적화
React 프로젝트를 진행하다 보면 데이터 Fetching과 관련된 코드를 여러 컴포넌트에서 반복적으로 작성하게 된다. 이런 반복을 줄이고 코드의 재사용성을 높이기 위해 Custom Hook을 활용할 수 있다. 이번 글에서는 데이터를 Fetching하기 위한 Custom Hook을 만들고 사용하는 과정을 정리해 보았다.
1. 기존 데이터 Fetching 코드
기존의 Fetching 로직은 아래와 같은 형태로 작성된다.
const [availablePlaces, setAvailablePlaces] = useState([]); // 데이터 상태
const [isLoading, setIsLoading] = useState(false); // 로딩 상태
const [error, setError] = useState(null); // 에러 상태
useEffect(() => {
async function fetchPlaces() {
setIsLoading(true);
try {
const response = await fetch('http://localhost:3000/places'); // API 호출
const resData = await response.json();
if (!response.ok) {
throw new Error(resData.message || 'Could not fetch places.');
}
setAvailablePlaces(resData.places); // 상태 업데이트
} catch (error) {
setError({ message: error.message || 'Failed to fetch places' }); // 에러 처리
}
setIsLoading(false); // 로딩 종료
}
fetchPlaces();
}, []);
이 코드는 데이터를 가져오는 데 필요한 상태 관리(useState), 로딩 처리, 에러 핸들링 등 필수 요소를 포함하고 있지만, 여러 컴포넌트에서 반복적으로 작성해야 한다는 단점이 있다.
2. Custom Hook 작성
반복적인 Fetching 로직을 Custom Hook으로 추출하여 코드 재사용성을 높일 수 있다.
import { useEffect, useState } from 'react';
export function useFetch(fetchFn, initialValue) {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [fetchedData, setFetchedData] = useState(initialValue);
useEffect(() => {
async function fetchData() {
setIsLoading(true);
try {
const data = await fetchFn(); // fetchFn 실행
setFetchedData(data); // 데이터 상태 업데이트
} catch (error) {
setError({ message: error.message || 'Failed to fetch data' }); // 에러 처리
}
setIsLoading(false); // 로딩 종료
}
fetchData();
}, [fetchFn]);
return {
isLoading,
error,
fetchedData,
};
}
3. Custom Hook의 주요 포인트
- Hook 이름 규칙:
React에서 Custom Hook은 이름이 반드시 use로 시작해야 한다. 예를 들어, useFetch라는 이름은 React가 이 함수를 Hook으로 인식하게 한다. 단, React의 기본 Hook 이름(useState, useEffect)과 겹치지 않도록 주의해야 한다. - 매개변수 활용:
- fetchFn: 데이터를 가져오는 비동기 함수로, API 호출 로직을 포함한다.
- initialValue: 초기 상태 값을 설정한다.
- 상태 관리:
- isLoading: 로딩 상태를 나타낸다.
- error: 발생한 에러를 저장한다.
- fetchedData: Fetching된 데이터를 저장한다.
- 결과 반환:
return을 통해 필요한 상태와 데이터를 반환하면, Hook을 사용하는 컴포넌트에서 쉽게 활용할 수 있다.
4. Custom Hook 사용 예시
Custom Hook을 사용하여 데이터를 Fetching하는 컴포넌트를 작성해 보자.
const {
isLoading,
error,
fetchedData: availablePlaces,
} = useFetch(fetchSortedPlaces, []);
- Object Destructuring: fetchedData를 availablePlaces라는 이름으로 변경.
- Hook에서 반환된 상태를 활용하여 로딩 중, 에러 발생, 데이터 출력 상태를 간단히 구현.
5. 정렬된 데이터 Fetching 함수
Fetching된 데이터를 정렬하기 위해 추가 로직을 포함한 비동기 함수(fetchSortedPlaces)를 작성할 수 있다.
async function fetchSortedPlaces() {
const places = await fetchAvailablePlaces();
return new Promise((resolve) => {
navigator.geolocation.getCurrentPosition((position) => {
const sortedPlaces = sortPlacesByDistance(
places,
position.coords.latitude,
position.coords.longitude
);
resolve(sortedPlaces);
});
});
}
Promise를 사용한 이유
- navigator.geolocation.getCurrentPosition은 비동기 작업을 콜백으로 처리한다.
- async/await는 Promise 기반으로 동작하기 때문에, 콜백을 Promise로 감싸야 await로 사용할 수 있다.
async/await를 사용한 이유
- 코드의 가독성을 높이고, 콜백 지옥(Callback Hell)을 피하기 위해 사용.
- 비동기 흐름을 동기 코드처럼 작성할 수 있어 직관적이다.
6. 최종 형태
이제 fetchSortedPlaces를 useFetch의 fetchFn으로 전달하여 정렬된 데이터를 Fetching할 수 있다.
const {
isLoading,
error,
fetchedData: sortedPlaces,
} = useFetch(fetchSortedPlaces, []);
isLoading과 error를 활용하여 로딩 화면과 에러 메시지를 표시하고, sortedPlaces로 데이터를 화면에 출력하면 된다.
7. 마무리
Custom Hook을 사용하면 반복적인 Fetching 로직을 줄이고 코드의 가독성과 재사용성을 높일 수 있다. 또한, async/await와 Promise를 함께 사용하여 비동기 작업을 더 효율적으로 처리할 수 있다. React 개발에서 Custom Hook은 코드 구조를 간결하게 만드는 중요한 도구이므로 적극적으로 활용해 보자! 😊
'Web & App > Frontend Study' 카테고리의 다른 글
| React #13 _ 유효성 검사 (1) | 2025.01.03 |
|---|---|
| React #12 _ Form 관리 (0) | 2025.01.02 |
| React에서 자주 쓰이는 용어 정리 (영어/한국어) (1) | 2025.01.02 |
| React # 10 Error handle (0) | 2025.01.02 |
| React # _ HTTP 요청 보내기 (1) | 2025.01.01 |