React 상태 관리, 서버·클라이언트 상태를 나누는 기준
“검색 결과까지 전역 상태에 넣었는데, 언제 다시 불러와야 할지 모르겠습니다.”
“모달을 열고 닫는 값과 API 응답이 한곳에 섞여 수정할 때마다 불안합니다.”
“전역 상태 라이브러리를 먼저 골라야 하는지, 컴포넌트 상태로 충분한지 판단이 어렵습니다.”
React 상태 관리는 라이브러리부터 고르는 일이 아니라, 값의 원본·공유 범위·생명주기를 먼저 구분하는 일입니다. 서버가 원본인 데이터는 요청과 갱신 흐름으로, 화면 상호작용을 위한 값은 가까운 UI의 책임으로 나누면 변경 이유와 영향 범위를 더 읽기 쉬워집니다.
알레오의 프론트엔드 개발자인 김알레오는 화면과 사용자 흐름을 설계할 때, 상태를 한 저장소에 모으기 전에 데이터 흐름과 갱신 주기를 먼저 그려 봅니다. 복잡한 화면일수록 저장 위치보다 무엇이 이 값을 바꾸는가를 기준으로 나누는 편이 판단에 도움이 됩니다.
어떤 값이 서버 상태이고, 어떤 값이 클라이언트 상태인가요?

API가 원본이고 요청·갱신·오류·최신성 판단이 필요한 값은 서버 상태로, 화면 상호작용을 위해 브라우저에서 만든 값은 클라이언트 상태로 분류할 수 있습니다. 둘 다 상태라는 이유만으로 같은 저장소와 규칙을 적용할 필요는 없습니다.
예를 들어 사용자 목록, 검색 결과, 페이지네이션으로 받아 온 항목은 서버가 원본입니다. 화면에서는 언제 요청할지, 이미 받은 결과를 재사용할지, 데이터 변경 뒤 무엇을 다시 확인할지를 정해야 합니다. 이 글의 설계 기준에서는 이런 값에 캐시와 재검증 흐름을 다루는 서버 상태 도구를 먼저 검토합니다.
반면 모달 열림 여부, 탭 선택, 드롭다운 표시 여부, 아직 제출하지 않은 입력값은 현재 화면의 상호작용에 가깝습니다. 값을 읽고 바꾸는 컴포넌트가 가깝다면 로컬 상태에 두는 편이 변경 경로를 이해하기 쉽습니다.
여러 화면이나 멀리 떨어진 컴포넌트가 같은 클라이언트 상태를 읽고 수정해야 한다면 전역 상태 라이브러리를 검토할 수 있습니다. 다만 공유 범위가 가까운 컴포넌트 트리에 머문다면, 상태를 상위 컴포넌트로 올리는 방식도 함께 비교해야 합니다.
상태 위치를 정하기 전 던질 네 가지 질문

아래 질문은 특정 라이브러리의 문법보다 먼저 적용할 수 있습니다.
- 원본은 어디에 있는가? 서버가 정답을 갖는지, 브라우저의 일시적 상호작용인지 확인합니다.
- 누가 읽고 수정하는가? 한 컴포넌트인지, 가까운 트리인지, 여러 화면인지 범위를 그립니다.
- 얼마나 유지되는가? 화면을 벗어나면 사라져도 되는지, 다시 방문했을 때 갱신하거나 재사용해야 하는지 봅니다.
- 외부 변경을 어떻게 반영하는가? 요청 중복, 갱신 뒤 화면 반영, 오류와 로딩을 어떤 흐름으로 처리할지 정합니다.
원본·공유 범위·생명주기·갱신 규칙에 답한 뒤에야 상태의 위치와 도구를 좁힐 수 있습니다.
서버 상태를 전역 저장소 하나에 모두 넣으면 왜 복잡해지나요?

전역 저장소에 서버 데이터를 둘 수는 있지만, 캐시·무효화·재요청 규칙까지 애플리케이션이 직접 책임져야 한다면 복잡성이 커질 수 있습니다. 단순한 UI 값까지 데이터 동기화 흐름에 넣으면 작은 화면 변경의 영향 범위도 커질 수 있습니다.
전역 저장소에 검색 결과를 보관했다고 가정해 보겠습니다. 검색 조건이 바뀔 때 기존 결과를 지울지, 유지한 채 새 요청을 보낼지, 같은 조건의 요청을 재사용할지, 항목 수정 뒤 어느 목록을 갱신할지를 각각 정해야 합니다. 이 규칙이 화면마다 흩어지면 어느 이벤트가 어느 데이터를 최신으로 만드는지 추적하기 어려워집니다.
서버 상태 도구를 검토하는 이유는 전역화를 피하기 위해서만이 아닙니다. 서버 원본 데이터에 필요한 요청·캐시·무효화 흐름을 별도 책임으로 다룰 수 있는지 확인하기 위해서입니다. 반대로 데이터 흐름이 단순하고 화면 하나에서만 쓰는 값이라면 새 계층을 추가하는 일이 과할 수 있습니다.
클라이언트 상태도 전역 라이브러리가 항상 답은 아닙니다. 가까운 컴포넌트 트리 안에서만 공유하는 탭 상태라면 상위 컴포넌트로 상태를 올려 전달하는 방식이 더 짧고 명료할 수 있습니다. 전역화 뒤에 상태의 생성·초기화 시점과 변경 주체를 별도로 설명해야 한다면 도입 효과를 다시 살펴볼 신호입니다.
검색 결과 화면에서는 캐시 키를 어떻게 설계하나요?
서버 응답을 바꾸는 검색어·필터·페이지 값은 결과를 식별하는 캐시 키에 반영하고, 화면 표시만 바꾸는 값은 별도로 둡니다. 핵심은 값이 필터처럼 보이는지가 아니라 서버 응답을 실제로 바꾸는지입니다.
| 값 | 권장 분류 | 판단 이유 |
|---|---|---|
| 검색어 | 서버 상태 요청의 입력 | 서버가 반환할 결과를 바꿀 수 있음 |
| 서버 처리 필터 | 서버 상태 요청의 입력 | 결과 집합을 구분해야 함 |
| 페이지 번호 | 서버 상태 요청의 입력 | 다른 결과 묶음을 요청할 수 있음 |
| 필터 패널 열림 여부 | 클라이언트 상태 | 화면 표시만 바꿈 |
| 입력 중인 임시 문구 | 로컬 클라이언트 상태 | 제출 전 상호작용에 가까움 |
TanStack Query 공식 문서는 queryFn 결과를 바꾸는 변수와 필터·식별자·페이지 조건을 queryKey에 포함해 데이터를 고유하게 설명하도록 안내합니다. 조건별 캐시를 분리하고 변수 변경에 따라 재조회하려는 목록 화면에 적용할 수 있는 원칙입니다. 출처: Query Keys
필터 패널 열림 여부처럼 서버 응답을 바꾸지 않는 UI 값은 위 공식 문서에서 직접 다루지 않습니다. 따라서 이 값은 캐시 키 규칙이 아니라 화면 상태의 책임으로 분리하는 설계 판단이 적절합니다.
검색어와 서버 처리 필터, 페이지 번호가 결과를 바꾼다면 해당 조합으로 요청과 캐시를 식별합니다. 필터가 바뀌면 새 조건으로 요청하고, 요청 중 이전 결과를 유지할지 로딩 상태를 우선할지는 화면 요구에 맞춰 정합니다.
이 구분은 코드 조직에도 영향을 줍니다. 서버 상태 영역에는 요청 함수, 결과 식별 기준, 갱신 뒤 무효화 규칙을 모으고, UI 상태 영역에는 표시 여부와 입력 상호작용을 둡니다. 컴포넌트 책임을 나누는 기준은 대규모 프론트엔드 프로젝트에서 폴더 구조와 컴포넌트 기준 세우는 법도 함께 참고할 수 있습니다.
라이브러리 도입 뒤에는 무엇이 줄었는지 확인해야 하나요?
도입 판단은 상태 저장소의 개수가 아니라 중복 요청, 갱신 누락, 경계 조건 처리 코드와 테스트의 복잡성이 줄었는지로 확인합니다. 설정만 늘고 해결되는 문제가 줄지 않았다면 현재 화면에는 과한 구성일 수 있습니다.
TanStack Query 공식 테스트 가이드는 테스트별로 격리된 QueryClient를 구성하고, 오류 테스트에서는 재시도를 끄며, 네트워크 호출과 페이지별 추가 요청을 검증하는 예시를 제시합니다. 이는 도입 효과를 보장하는 수치가 아니라, 요청·오류·캐시 관련 동작을 검증하는 방법입니다. 출처: Testing
실제 화면에서는 다음 항목을 함께 확인할 수 있습니다.
- 같은 조건에서 동일한 요청이 반복되는가
- 데이터 변경 뒤 관련 화면이 기대한 시점에 갱신되는가
- 로딩, 오류, 빈 결과를 각 화면이 일관되게 처리하는가
- 낙관적 업데이트가 실패했을 때 사용자가 이해할 수 있는 상태로 돌아오는가
- 개발 도구에서 요청과 캐시 변화의 이유를 추적할 수 있는가
빈 결과와 제품별 경계 조건은 애플리케이션 요구에 맞춰 별도로 정해야 합니다. 필터 변경, 요청 실패, 빈 결과, 저장 성공 뒤 목록 갱신처럼 사용자 흐름을 나누어 테스트하면 상태 분리의 빈틈을 찾기 쉽습니다. 구체적인 테스트 구성은 프론트엔드 테스트 자동화 구축 순서와 꼭 필요한 도구 정리에서 이어서 살펴볼 수 있습니다.
단순한 화면에도 서버 상태 도구가 필요한가요?
아닙니다. 화면 하나에서만 쓰고 갱신 규칙이 단순한 데이터라면 로컬 상태와 명확한 요청 처리만으로도 충분할 수 있습니다. 분리는 책임을 분명히 하기 위한 기준이지, 모든 상태에 별도 라이브러리를 추가하자는 규칙은 아닙니다.
폼은 특히 예외를 세심하게 봐야 합니다. 입력 중인 임시 값, 유효성 검사 결과, 제출 직전의 UI 제어는 로컬 상태에 머무는 경우가 많습니다. 제출 성공으로 서버 데이터가 바뀌었다면 그때 목록이나 상세 데이터의 갱신 규칙을 연결하면 됩니다.
반대로 여러 화면에서 같은 서버 데이터를 보고 갱신과 최신성 판단이 반복된다면 서버 상태 도구를 비교할 이유가 생깁니다. 먼저 도구를 정하기보다 현재 요청 흐름을 그린 뒤, 애플리케이션이 직접 관리 중인 규칙이 무엇인지 확인하는 순서가 낫습니다.
결론
React 상태 관리의 핵심 판단은 어떤 라이브러리가 더 유명한지가 아니라 이 값이 서버의 원본 데이터인지, 현재 화면의 상호작용인지입니다. 서버 원본 데이터에는 결과 식별·캐시·재요청·무효화 규칙을 검토하고, 화면 전용 값은 가능한 가까운 컴포넌트에 둡니다.
새 화면을 만들 때는 원본·공유 범위·생명주기·갱신 규칙을 먼저 적어 보세요. 답이 단순하다면 로컬 상태나 상위 컴포넌트로의 상태 끌어올리기로 충분할 수 있습니다. 답이 여러 화면의 캐시와 갱신으로 이어진다면 서버 상태 도구를 검토할 근거가 생깁니다.
자주 묻는 질문
서버 상태와 클라이언트 상태를 한 라이브러리에서 함께 관리하면 안 되나요?
함께 관리할 수는 있지만, 두 종류의 갱신 책임은 분리해야 합니다. 서버 데이터에는 최신성·캐시·무효화가, UI 상태에는 사용자 상호작용과 화면 생명주기가 연결되므로 한 저장소를 사용하더라도 책임이 섞이지 않게 설계해야 합니다.
검색어는 항상 서버 상태인가요?
아닙니다. 입력 중인 검색어는 로컬 값일 수 있고, 실제 서버 요청에 적용된 검색어는 결과를 구분하는 요청 입력값입니다. 입력값과 조회를 실행한 값을 나눌지는 검색 UX와 요청 시점에 따라 결정합니다.
여러 컴포넌트가 같은 UI 상태를 읽으면 바로 전역화해야 하나요?
아닙니다. 가까운 컴포넌트 트리에서만 공유한다면 상태를 상위로 올리는 방식을 먼저 비교할 수 있습니다. 전역화가 변경 경로나 초기화 규칙을 더 복잡하게 만드는지도 확인해야 합니다.
캐시 무효화가 제대로 됐는지는 어떻게 확인하나요?
데이터 변경 뒤 관련 화면이 기대한 결과로 갱신되는지와 동일 요청이 불필요하게 반복되지 않는지를 함께 확인합니다. 로딩·오류·빈 결과와 갱신 실패도 테스트 시나리오에 포함하는 편이 좋습니다.
제 도움이 필요하시다면
React 화면에서 상태의 출처와 데이터 흐름을 정리하거나, 검색·목록·상세 화면의 컴포넌트 책임을 나누는 일이 필요하다면 프론트엔드 관점에서 함께 검토할 수 있습니다. 전역 상태가 커져 변경 영향 범위를 파악하기 어렵거나 API 응답 갱신과 UI 상태가 뒤섞인 경우에, 현재 흐름을 먼저 그려 보는 방식이 유용합니다.
웹 서비스의 화면 구조와 콘텐츠 운영 환경을 함께 고려해야 한다면 알레오 시작하기를 통해 문의할 수 있습니다.




