React 상태를 무조건 전역으로 만들면 생기는 문제
React를 처음 공부할 때 상태 관리가 어려워지면 전역 상태 라이브러리를 떠올리기 쉽습니다. Zustand, Redux, Jotai 같은 도구들은 분명 유용하지만, 모든 상태를 전역으로 빼면 오히려 프로젝트가 더 복잡해질 수 있습니다.
저도 예전에는 props 전달이 조금만 귀찮아져도 “이거 전역 상태로 빼면 편하지 않을까?”라고 생각했습니다. 그런데 나중에는 어떤 컴포넌트가 상태를 바꾸는지 추적하기 어려워졌습니다.
지역 상태로 충분한 경우
한 컴포넌트 안에서만 쓰는 값은 대부분 지역 상태로 충분합니다.
const [isOpen, setIsOpen] = useState(false);
예를 들어 모달 열림 여부, 입력창 값, 탭 선택 상태처럼 특정 UI에만 필요한 값은 굳이 전역으로 만들 필요가 없습니다.
이런 상태를 전역으로 올리면 다른 파일에서도 접근할 수 있게 되지만, 동시에 변경 가능한 위치가 늘어납니다. 작은 UI 상태가 전역 저장소에 쌓이면 저장소가 금방 지저분해집니다.
부모 상태로 두는 게 나은 경우
형제 컴포넌트가 같은 상태를 공유해야 한다면 가장 가까운 공통 부모에 상태를 두는 방법이 좋습니다.
function Page() {
const [selectedId, setSelectedId] = useState<string | null>(null);
return (
<>
<List onSelect={setSelectedId} />
<Detail id={selectedId} />
</>
);
}
이 정도 구조는 전역 상태 없이도 충분히 이해하기 쉽습니다. 상태의 소유자가 페이지 컴포넌트라는 점도 명확합니다.
전역 상태가 필요한 경우
전역 상태가 필요한 경우도 분명 있습니다.
- 로그인한 사용자 정보
- 테마 설정
- 여러 페이지에서 공유하는 장바구니
- 앱 전체에서 필요한 알림 상태
- 깊은 컴포넌트 트리에서 자주 쓰는 설정값
이런 값은 여러 위치에서 읽고 변경할 수 있어야 하므로 전역 상태가 어울립니다.
서버 상태와 클라이언트 상태 구분하기
또 하나 중요한 건 서버에서 가져온 데이터를 전역 상태로 직접 관리하려고 하지 않는 것입니다.
예를 들어 게시글 목록, 사용자 목록, 댓글 목록 같은 데이터는 서버 상태입니다. 이런 데이터는 React Query나 SWR처럼 캐싱과 재요청을 처리해주는 도구가 더 잘 맞습니다.
const { data, isLoading } = useQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
서버 상태를 직접 전역 store에 넣으면 새로고침, 캐시 무효화, 에러 처리까지 직접 챙겨야 해서 복잡해질 수 있습니다.
내가 쓰는 기준
상태 위치를 정할 때는 보통 이렇게 생각합니다.
- 한 컴포넌트만 쓰면 지역 상태
- 형제 컴포넌트끼리 공유하면 공통 부모 상태
- 앱 전체에서 필요하면 전역 상태
- API에서 온 데이터면 서버 상태 관리 도구 고려
마무리
전역 상태는 강력하지만, 많이 쓴다고 좋은 구조가 되는 것은 아닙니다. 오히려 상태가 어디서 바뀌는지 알기 어려워질 수 있습니다.
React에서 상태 관리는 “어떤 도구를 쓰느냐”보다 “상태를 어디에 둘 것인가”가 더 중요하다고 느꼈습니다. 처음에는 최대한 가까운 곳에 상태를 두고, 정말 필요할 때만 전역으로 올리는 방식이 가장 안전합니다.