- 경쟁 상태: 이전 요청 결과가 나중에 도착
- 중복 요청: 같은 데이터를 여러 컴포넌트가 각각 요청
- 캐시 없음: 화면을 오갈 때마다 다시 로딩
- 갱신 시점: 다른 화면에서 수정한 내용이 반영되지 않음
- 정리 누락: 사라진 컴포넌트의 상태를 갱신
이 파트에서 다루는 내용
직접 만들면 처음에는 간단해 보입니다
이펙트 안에서 데이터를 가져와 상태에 넣는 코드는 몇 줄이면 됩니다. 문제는 화면이 실제로 요구하는 조건들이 하나씩 붙기 시작할 때입니다.
// 처음: 간단해 보입니다
const [orders, setOrders] = useState([]);
useEffect(() => {
fetchOrders().then(setOrders);
}, []);
// 실제로 필요한 것들
const [orders, setOrders] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let ignore = false;
setIsLoading(true);
setError(null);
fetchOrders(keyword)
.then((data) => { if (!ignore) setOrders(data); })
.catch((err) => { if (!ignore) setError(err); })
.finally(() => { if (!ignore) setIsLoading(false); });
return () => { ignore = true; };
}, [keyword]);여기까지 와도 캐시, 재요청, 중복 요청 제거, 화면 복귀 시 갱신은 아직 없습니다. 화면마다 이 코드를 반복하게 되는 것이 진짜 문제입니다.
서버 상태는 지역 상태와 성질이 다릅니다
지역 상태는 우리가 원본을 갖고 있어 항상 정확합니다. 서버 상태는 원본이 서버에 있고 우리 화면은 사본을 보여 주는 것뿐입니다.
그래서 서버 상태에는 지역 상태에 없는 문제가 따라옵니다. 우리가 보고 있는 값이 이미 낡았을 수 있고, 언제 다시 가져올지 정해야 합니다.
- 항상 최신
- 동기적으로 변경
- 실패가 없음
- 낡을 수 있음
- 비동기이며 실패할 수 있음
- 여러 사용자가 동시에 바꿈
- 캐시와 갱신 시점 판단이 필요
서버 상태를 useState로 다루면 위 차이를 모두 직접 처리해야 합니다. 전용 도구를 쓰는 이유는 편해서가 아니라, 이 문제들이 이미 정리된 형태로 제공되기 때문입니다.
서버 상태 도구가 해결하는 것
TanStack Query 같은 서버 상태 전용 도구는 데이터를 가져오는 방법을 바꾸는 것이 아니라, 가져온 뒤의 관리 방식을 제공합니다.
같은 키의 데이터를 여러 컴포넌트가 요청해도 한 번만 가져오고 결과를 공유합니다.
매번 세 개의 상태를 만들 필요가 없습니다. 조회 결과와 함께 상태를 받습니다.
화면 복귀, 재연결, 일정 시간 경과 같은 조건에 따라 다시 가져옵니다. 조건은 설정으로 조절합니다.
데이터를 수정한 뒤 관련 조회를 무효화하면 화면이 자동으로 최신 상태가 됩니다. 직접 목록을 손보지 않아도 됩니다.
서버 응답을 기다리지 않고 화면을 먼저 바꾸고, 실패하면 되돌립니다. 되돌리기 처리를 빠뜨리지 않는 것이 중요합니다.
요청 키 단위로 관리하므로 이전 응답이 최신을 덮어쓰는 문제가 기본적으로 해결됩니다.
로딩과 오류는 화면 설계의 일부입니다
도구를 쓰더라도 무엇을 보여 줄지는 직접 정해야 합니다. 로딩과 오류 처리를 나중에 붙이면 화면이 어색해집니다.
처음 데이터를 기다릴 때와 이미 있는 데이터를 새로 가져올 때를 다르게 표시합니다. 갱신마다 화면이 비면 깜빡임이 생깁니다.
데이터가 0건인 경우와 로딩 중인 경우는 다릅니다. 빈 목록 안내를 따로 준비합니다.
화면 전체를 오류로 덮을지, 해당 영역만 표시할지 정합니다. 목록 하나가 실패했다고 페이지 전체를 못 쓰게 만들 필요는 없습니다.
일시적 오류일 수 있으므로 다시 시도할 수단을 줍니다. 새로고침만이 유일한 방법이 되지 않게 합니다.
서버가 내려준 오류 코드로 분기하고, 사용자에게는 다듬은 문구를 보여 줍니다. 응답 원문을 그대로 노출하지 않습니다.
언제 도구를 도입할지
- 서버 데이터를 다루는 화면이 여러 개
- 같은 데이터를 여러 곳에서 조회
- 수정 후 목록 갱신이 반복적으로 필요
- 로딩·오류 처리 코드가 화면마다 복사되고 있음
- 조회 화면이 한두 개뿐
- 데이터가 거의 바뀌지 않음
- 학습 목적의 작은 프로젝트
직접 구현이 나쁜 것은 아닙니다. 다만 같은 로딩·오류·갱신 코드를 세 번째 복사하고 있다면 그것이 도입 신호입니다. 그 시점에는 이미 각 화면의 처리 방식이 조금씩 달라져 있을 가능성이 큽니다.
버전별 참고
본문은 React 19 기준입니다. 18과 달라지는 부분은 아래에 정리합니다.
- React 19에는 프로미스를 읽는 use API와 비동기 전환 관련 훅이 추가돼, 간단한 경우 직접 구현 코드가 짧아집니다.
- 다만 캐시와 갱신 전략은 여전히 별도 도구의 영역입니다. React 자체가 서버 상태 관리를 대체하지는 않습니다.
- Suspense를 활용한 로딩 처리는 18 이상에서 쓸 수 있으며, 사용하는 데이터 도구가 지원하는지 확인이 필요합니다.