1. 들어가며
최근 프로젝트에서 React 18과 React Query를 활용하여 서버 상태 관리 최적화를 진행했습니다.
기존 방식에서는 불필요한 API 요청이 많아 성능 문제가 있었고, 이를 React Query로 개선하면서 어떤 점이 효과적이었는지 공유하려 합니다.
특히,
✅ React 18의 자동 배치(Auto Batching) 기능이 성능에 미친 영향
✅ React Query를 활용한 API 요청 최적화
✅ 불필요한 리렌더링을 줄이기 위한 전략
에 대해 다룰 예정입니다.
2. 실무에서 적용한 핵심 기술
2.1 React 18 – 자동 배치(Auto Batching)
React 18에서는 여러 개의 setState가 자동으로 하나의 렌더링으로 합쳐지는 자동 배치(Auto Batching) 기능이 도입되었습니다.
📌 기존 방식 (React 17) – 여러 번 렌더링 발생
const handleClick = () => {
setCount(count + 1);
setMessage("Updated!");
};
console.log("Component re-rendered");
✅ handleClick 실행 시 setState가 2번 호출되므로, 2번 렌더링 발생
Component re-rendered
Component re-rendered
🚀 개선된 방식 (React 18) – 자동 배치 적용
const handleClick = () => {
setCount(count + 1);
setMessage("Updated!");
};
console.log("Component re-rendered");
✅ handleClick 실행 시 여러 개의 setState가 자동으로 배치되어 한 번만 렌더링 발생
Component re-rendered
🚀 결과: 상태 업데이트 시 평균 렌더링 횟수가 20% 감소하여 성능이 향상됨
2.2 React Query – API 요청 최적화
기존에는 Redux를 사용하여 API 데이터를 관리했지만, 다음과 같은 문제점이 있었습니다.
❌ 불필요한 API 요청 – 새로고침할 때마다 동일한 데이터를 다시 가져옴
❌ 복잡한 상태 관리 – 로딩, 에러 처리 코드를 직접 관리해야 함
❌ 비효율적인 캐싱 – 기존 데이터 유지 없이 새로운 데이터를 매번 요청
React Query를 적용하면서 이를 해결할 수 있었습니다.
🚀 React Query 적용 후 변화
const { data, refetch } = useQuery(['updateList'], fetchUpdateList, {
staleTime: 1000 * 60 * 5, // 5분 동안 캐싱 유지
enabled: false, // 최초 실행 방지
});
✅ API 요청 횟수가 약 40% 감소
✅ React Query DevTools로 확인한 결과, 네트워크 요청이 최적화됨
✅ 서버 상태를 자동 관리하면서 불필요한 로딩 상태 코드가 줄어듦
3. 주요 문제 해결 사례
3.1 staleTime과 refetch 설정 이슈
📌 문제: staleTime을 짧게 설정하여 불필요한 API 요청이 많이 발생
📌 해결: staleTime을 5분으로 설정하고, 필요할 때만 refetch 호출하도록 변경
const { data, refetch } = useQuery(['updateList'], fetchUpdateList, {
staleTime: 1000 * 60 * 5, // 5분 동안 동일한 데이터 사용
enabled: false, // 최초 실행 방지
});
<button onClick={() => refetch()}>업데이트 목록 불러오기</button>
✅ API 요청 횟수가 줄어들어 성능 최적화됨
3.2 useEffect에서 불필요한 API 요청 문제
📌 문제: useEffect에서 API 요청을 실행할 때 의존성 배열 설정 오류로 인해 중복 요청 발생
📌 해결: useEffect 대신 React Query의 enabled 옵션을 활용하여 특정 조건에서만 실행되도록 변경
const { data, isLoading } = useQuery(['updateList'], fetchUpdateList, {
enabled: shouldFetch, // 특정 조건이 true일 때만 실행
});
✅ 불필요한 API 호출 방지 & 더 명확한 데이터 로딩 로직 구현
3.3 비동기 업데이트(useMutation) 최적화
📌 문제: 기존 방식에서는 데이터를 업데이트한 후 전체 목록을 다시 refetch하여 성능 저하 발생
📌 해결: React Query의 useMutation을 사용하여 낙관적 업데이트(Optimistic Update) 적용
import { useMutation, useQueryClient } from '@tanstack/react-query';
const queryClient = useQueryClient();
const mutation = useMutation(updateItem, {
onMutate: async (newItem) => {
queryClient.setQueryData(['updateList'], (oldData) =>
oldData?.map(item => item.id === newItem.id ? { ...item, ...newItem } : item)
);
},
onSuccess: () => {
queryClient.invalidateQueries(['updateList']); // 최신 데이터 동기화
}
});
✅ API 응답을 기다리지 않고 즉시 UI 업데이트 가능
✅ 불필요한 전체 데이터 refetch 감소 → 성능 최적화
4. 마치며
이번 프로젝트에서 React 18과 React Query를 활용하면서 많은 인사이트를 얻었습니다.
✅ React 18의 자동 배치 덕분에 불필요한 리렌더링이 줄어듦
✅ React Query를 활용하면 서버 상태 관리를 더욱 효율적으로 할 수 있음
✅ staleTime, enabled, useMutation 등을 적절히 조절하면 API 요청 최적화 가능
'React' 카테고리의 다른 글
이 작은 차이가 성능을 바꾼다! key={index} vs key={id} (0) | 2025.03.18 |
---|---|
React 18에서 효율적인 컴포넌트 설계란? (0) | 2025.03.18 |