전체 목록
ReactMedium#105

서버 상태(Server State)와 클라이언트 상태(Client State)의 차이를 설명해주세요.

#React#상태관리#서버상태#캐싱

답변 포인트

서버가 원본 데이터를 가지고 있는지, 캐싱과 재검증이 필요한지 기준으로 구분해보세요.

정답 및 해설

빠른 요약

클라이언트 상태는 모달 열림 여부, 선택된 탭, 폼 입력값처럼 브라우저 안에서만 의미 있는 UI 상태입니다. 서버 상태는 사용자 정보, 게시글 목록, 장바구니처럼 원본이 서버에 있고 클라이언트가 복사본을 캐시하는 상태입니다.

프론트엔드 상태는 크게 클라이언트 상태와 서버 상태로 나눌 수 있습니다. 둘을 구분하면 React state, Context, Redux, Zustand, TanStack Query 같은 도구를 언제 써야 하는지 판단하기 쉬워집니다.

클라이언트 상태

클라이언트 상태는 브라우저 안에서만 의미가 있고, 서버가 정답을 가지고 있지 않은 상태입니다.

예:

  • 모달 열림 여부
  • 현재 선택된 탭
  • 다크 모드 여부
  • 폼 입력 중 임시 값
  • 드롭다운 열림 여부
TSX
const [isOpen, setIsOpen] = useState(false);
const [selectedTab, setSelectedTab] = useState("profile");

이런 상태는 보통 useState, useReducer, Context, Zustand 등으로 관리합니다.

서버 상태

서버 상태는 원본 데이터가 서버에 있고, 클라이언트는 그 복사본을 캐시해서 사용하는 상태입니다.

예:

  • 사용자 프로필
  • 게시글 목록
  • 장바구니 데이터
  • 알림 목록
  • 권한 정보

서버 상태는 단순히 값을 저장하는 것보다 더 많은 문제가 따라옵니다.

  • 로딩 상태
  • 에러 상태
  • 캐싱
  • 재요청
  • 백그라운드 갱신
  • 중복 요청 제거
  • 낙관적 업데이트
  • 페이지네이션

직접 useEffect로 처리할 때의 한계

TSX
function UserProfile({ userId }: { userId: string }) {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    setIsLoading(true);

    fetch(`/api/users/${userId}`)
      .then((res) => res.json())
      .then(setUser)
      .catch(setError)
      .finally(() => setIsLoading(false));
  }, [userId]);

  // 캐싱, 중복 요청 제거, stale 처리 등을 직접 구현해야 함
}

간단한 화면에서는 괜찮지만, 앱이 커질수록 반복 코드와 상태 불일치가 늘어납니다.

TanStack Query 같은 도구의 역할

TSX
function UserProfile({ userId }: { userId: string }) {
  const { data, isLoading, error } = useQuery({
    queryKey: ["user", userId],
    queryFn: () => fetchUser(userId),
  });

  if (isLoading) return <p> </p>;
  if (error) return <p> </p>;

  return <p>{data.name}</p>;
}

서버 상태 라이브러리는 데이터를 "전역 상태"로 저장한다기보다, 서버 데이터 캐시를 관리합니다.

판단 기준

질문적합한 상태
서버가 원본 데이터를 가지고 있나요?서버 상태
시간이 지나면 stale해질 수 있나요?서버 상태
refetch, cache, retry가 필요한가요?서버 상태
UI에서만 의미가 있나요?클라이언트 상태
페이지를 새로고침하면 사라져도 괜찮나요?클라이언트 상태

정리

클라이언트 상태는 UI의 현재 상태를 표현하고, 서버 상태는 원격 데이터의 캐시를 표현합니다. 서버 데이터를 Redux나 Context에 무조건 넣기보다, 서버 상태 관리 도구를 사용하면 로딩, 캐싱, 재검증 같은 문제를 일관되게 처리할 수 있습니다.

서버 상태와 클라이언트 상태의 본질적 차이

서버 상태는 원본이 서버에 있고 여러 사용자가 공유할 수 있는 비동기 데이터입니다. 클라이언트 상태는 현재 브라우저 UI를 표현하기 위한 로컬 데이터입니다.

TSX
// 서버 상태: 원본은 API/DB에 있음
const { data: user, isLoading } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
});

// 클라이언트 상태: 현재 화면의 UI 상태
const [isModalOpen, setModalOpen] = useState(false);

서버 상태가 어려운 이유

  • 로딩/에러/재시도 상태가 필요합니다.
  • 캐시가 오래되었는지(stale) 판단해야 합니다.
  • 같은 데이터를 여러 컴포넌트에서 공유합니다.
  • mutation 이후 무효화나 optimistic update가 필요합니다.

선택 기준

상태예시주로 사용하는 도구
서버 상태사용자 정보, 게시글 목록, 주문 내역TanStack Query, SWR, Apollo
클라이언트 상태모달 열림, 탭 선택, 입력 중 값useState, useReducer, Zustand
URL 상태페이지 번호, 필터, 검색어query string, router

서버 상태를 전역 store에 직접 넣으면 캐시 무효화, 중복 요청 제거, 재시도 같은 문제를 직접 해결해야 합니다. 그래서 서버 상태 전용 라이브러리를 쓰는 편이 유지보수에 유리합니다.

관련 질문

같은 카테고리/태그 기준