Skip to Content
WebReactReact 실무01. 서버 상태는 왜 따로 다뤄야 하는가

이번 편의 결과물: bookshelf의 현재 데이터 흐름(로컬 배열 + useBooks)에서 어떤 지점이 실제 서버와 연결되면 깨지는지 짚어봅니다. 코드는 바꾸지 않습니다. · 다루는 개념: 서버 상태/클라이언트 상태 구분, 캐시·정합성 문제, 전역 스토어에 서버 데이터를 넣었을 때 깨지는 지점, TanStack Query가 해결하는 문제

이 편에서 만드는 파일

이 편은 개념 편입니다. 새로 만들거나 고치는 파일이 없습니다. 대신 react_2를 마친 bookshelf의 기존 파일을 근거로 문제를 짚습니다.

bookshelf/src/ ├── hooks/useBooks.js ← 지금은 localStorage 기반. 04편부터 서버 조회로 바뀔 대상 └── pages/BookListPage.jsx ← 지금은 useBooks가 준 배열을 그대로 렌더링

개념 정리

클라이언트 상태와 서버 상태는 다른 문제다

useStateuseReducer로 다루는 값(입력 폼 값, 모달 열림 여부, 정렬 기준)은 클라이언트 상태입니다. 이 값의 원본은 화면 자체이고, 컴포넌트가 값을 100퍼센트 소유합니다. 반면 책 목록처럼 서버 어딘가에 저장된 데이터를 화면에 보여주는 값은 서버 상태입니다. 화면은 그 데이터의 스냅샷일 뿐이고, 원본은 언제든 다른 요청·다른 사용자·다른 탭에 의해 바뀔 수 있습니다.

구분클라이언트 상태서버 상태
원본 위치컴포넌트(메모리)서버(DB, API)
소유권화면이 완전히 소유화면은 사본만 가짐
변경 방식setState 호출네트워크 요청 후 응답 반영
동시성 문제없음(단일 탭 안에서만 존재)있음(다른 클라이언트가 먼저 바꿀 수 있음)
항상 따라오는 상태값 자체로딩·에러·성공 3가지

지금의 useBooks는 왜 아직 괜찮았는가

useBooks.jslocalStorage를 원본으로 씁니다. localStorage는 같은 브라우저·같은 탭 안에서는 사실상 동기적으로 읽고 쓸 수 있어서, 서버 상태의 어려움(네트워크 지연, 동시 수정, 캐시 무효화)이 드러나지 않았습니다. 04편부터 데이터 원본이 실제 API(json-server)로 바뀌면 상황이 달라집니다.

전역 스토어에 서버 데이터를 그대로 넣으면 깨지는 지점

Context나 Zustand 같은 클라이언트 상태 도구에 API 응답을 그대로 저장하는 방식은 흔한 실수입니다. 다음 질문에 답이 없기 때문입니다.

  • 이 데이터는 언제 오래된(stale) 것으로 취급하고 다시 가져올 것인가
  • 같은 데이터를 두 컴포넌트가 동시에 요청하면 요청을 한 번으로 합칠 것인가
  • 요청이 실패하면 누가 재시도하고, 몇 번까지 재시도할 것인가
  • 화면을 벗어났다가 돌아왔을 때 캐시를 재사용할 것인가, 새로 가져올 것인가

이 네 가지를 직접 구현하려면 useEffect 안에 로딩·에러 플래그, 타이머, 요청 취소 로직이 쌓입니다. 기능이 늘수록 같은 코드가 컴포넌트마다 반복됩니다.

TanStack Query가 대신 맡는 것

TanStack Query는 서버 상태를 위한 전용 캐시 계층입니다. queryKey(예: ['books'])로 데이터를 식별하고, staleTime이 지나면 자동으로 다시 가져오며, 같은 키로 들어온 요청은 하나로 합칩니다. 로딩·에러·성공 상태도 훅이 직접 관리해 반환합니다. 04편부터 이 역할을 useQueryuseMutation에 맡깁니다.

직접 해보기

지금의 BookListPage.jsx를 읽고, “만약 useBooks가 fetch로 서버에서 책 목록을 가져온다면” 어떤 코드가 추가로 필요할지 목록으로 적어보세요.

로딩 중 화면, 에러 화면, 데이터가 바뀐 뒤 다시 가져오는 로직, 요청이 겹칠 때 중복 제거 로직이 필요합니다. 04편에서 이 목록을 useQuery 옵션 하나로 대체하는 과정을 확인합니다.

자주 하는 실수

증상원인고치는 법
화면 전환마다 API를 다시 호출한다캐시 없이 useEffect로 매번 fetchqueryKey 기반 캐시로 재사용
같은 데이터가 컴포넌트마다 따로 로딩된다전역 스토어 없이 각자 fetch같은 queryKey를 쓰면 요청이 자동으로 합쳐짐
서버 데이터가 오래돼도 화면이 안 바뀐다갱신 시점을 정하지 않음staleTime으로 언제 다시 가져올지 명시

확인 문제

문제 14지선다
클라이언트 상태와 서버 상태를 구분하는 가장 핵심적인 기준은 무엇입니까
문제 24지선다
서버 상태에는 항상 따라오지만 클라이언트 상태에는 보통 필요 없는 것은 무엇입니까
문제 34지선다
전역 스토어에 API 응답을 그대로 저장했을 때 스스로 해결되지 않는 문제는 무엇입니까
문제 44지선다
지금의 bookshelf hooks/useBooks.js가 서버 상태의 어려움을 아직 겪지 않은 이유는 무엇입니까
문제 54지선다
TanStack Query가 queryKey로 하는 일로 옳은 것은 무엇입니까

참고 자료

Last updated on