본문 바로가기
framework_library/react

전역 상태는 왜 마지막 카드인가

by 죄니안죄니 2026. 1. 10.
전역 상태는 왜 마지막 카드인가전역 상태는 왜 마지막 카드인가전역 상태는 왜 마지막 카드인가
 
 
 

전역 상태는 왜 마지막 카드인가

대부분의 전역 상태는 사실 필요 없었던 이유

React를 쓰다 보면 반드시 이 지점에 도착한다.

“이거 여러 군데서 쓰이는데…
전역으로 빼야 하는 거 아냐?”

그리고 어느 순간
Context, Zustand, Redux가 한꺼번에 들어온다.
그 뒤부터 디버깅이 느려지고, 원인 추적이 어려워진다.

이 글의 목적은 단순하다.

  • ❌ 전역 상태를 쓰지 말자는 얘기 아님
  • 언제 ‘진짜로’ 필요한지 선을 긋자

1️⃣ 대부분의 전역 상태가 필요 없었던 이유

실무에서 전역으로 올린 상태를 보면 패턴이 거의 같다.

❌ 전역으로 올려진 흔한 것들

  • 모달 열림 여부 -> 모달을 소유한 컴포넌트가 state를 가지는게 원칙. (어디서든 띄워야하는 시스템모달은 전역)
  • 특정 페이지의 검색 조건(페이지를 떠나면 초기화되도 문제없는 UX는 로컬상태. (검색조건이 유지 혹은 공유해야하는 경우 예외로 하거나 URL query, 상위레이아웃state같은 반전역 구조 활용)
  • 탭 선택 상태 
  • 폼 입력 중간값 (폼 제출 결과값은 전역으로 올림)

이 상태들의 공통점은 이거다.

화면에 종속된 상태다. 새로고침/이동 후에도 초기화 되도 되는 경우는 로컬이다. 
(아니라면 전역 or URL or 서버)
전역 상태는 편해서 쓰는 저장소가 아니라,
**시스템의 진실(source of truth)**만 올리는 곳이다.

그런데 전역으로 올리는 순간
이 상태들은 화면 생명주기와 분리된다.

결과

  • 화면은 사라졌는데 상태는 남아 있고
  • 다음 화면에서 “왜 이 값이 있지?”가 된다
  • 초기화 타이밍을 따로 관리해야 한다

👉 전역 상태가 문제를 해결한 게 아니라
문제를 이동시킨 것
이다.


2️⃣ “여러 컴포넌트에서 쓰면 전역?” → 틀렸다

이 오해가 가장 치명적이다.

“형제 컴포넌트에서 같이 쓰니까 전역 상태지?”

아니다.

여러 컴포넌트에서 사용
≠
앱 전반에서 사용

예시를 보자.

<Page>
  <SearchBar />
  <SearchResult />
</Page>

이 상태는:

  • 여러 컴포넌트가 쓰긴 하지만
  • 페이지를 벗어나면 의미가 사라진다

👉 이런 상태의 주인은 Page다.
전역이 아니라 페이지 로컬 상태다.


3️⃣ 전역 상태의 진짜 조건 (이거 아니면 쓰지 마라)

아래 조건을 모두 만족할 때만 전역을 고려한다.

1. 여러 화면에서 동시에 필요하다
2. 화면 전환 후에도 유지돼야 한다
3. 누가 바꿔도 의미가 동일하다
4. 앱 전체의 동작에 영향을 준다

전형적인 전역 상태

  • 로그인 사용자 정보(부서, 역할..)
    서버 -> Filter/Middleware 에서 한 번 세팅
    프론트 -> App 시작 시 컨텍스트 구성 화면마다 TokenService.getUser() ;  ❌
//1안- 앱 시작 시 (추천)
// index.tsx
//Vue의 app.use(store) 이후, mount 이전과 1:1 대응
store.dispatch(initAuth());

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

//2안- UI컴포넌트 
// App.tsx
useEffect(() => {
  dispatch(initAuth());
}, []);

// 사용시
computed(() => store.getters["auth/getUser"])

//Redux기준
import { useSelector } from "react-redux";

const user = useSelector((state) => state.auth.user);
const isLoggedIn = useSelector((state) => state.auth.loggedIn);

//실제 JSX 사용 예
function Header() {
  const user = useSelector((state) => state.auth.user);

  if (!user) return null;

  return (
    <div>
      {user.userNm} 님 환영합니다
    </div>
  );
}
더보기

//vue

// app.use(store) 이후, app.mount() 이전

app.use(routes);
app.use(store);

// ✅ 앱 부팅 시 전역 상태 초기화 (브라우저 새로고침 마찬가지 store, 전역변수, context 전부 초기화)
store.dispatch("auth/initAuth");

app.mount("#app");

//화면에서 전역상태만 보면 됨
import { computed } from "vue";
import { useStore } from "vuex";

const store = useStore();

const user = computed(() => store.getters["auth/getUser"]);
const isLoggedIn = computed(() => store.getters["auth/isLoggedIn"]);

<button v-if="isLoggedIn">
  {{ user.userNm }} 님 환영합니다
</button>

  • 인증 토큰 / 권한
  • 테마 (다크모드)
  • 언어 설정
  • 전역 알림 카운트, 인터셉터(401, 403)에서 강제로 띄우는 팝업(모달이라기보다 시스템 UI)

 

 
// 이런 것들
user
isAuthenticated
theme
locale

👉 이건 UI 상태가 아니라 앱 상태다.


4️⃣ Context / Zustand / Redux는 “범위”의 문제다

도구 선택은 철학 문제가 아니다.
상태의 범위(scope) 문제다.


🔹 Context — “정적이고 드물게 바뀌는 값”

적합한 경우:

  • 테마
  • 언어
  • 인증 정보
<ThemeProvider value="dark">
  <App />
</ThemeProvider>

부적합한 경우:

  • 잦은 변경
  • 리스트 데이터
  • 복잡한 업데이트 로직

이유:
👉 Context 변경 = 하위 전부 렌더 후보


🔹 Zustand — “여러 페이지에서 쓰는 동적 상태”

적합한 경우:

  • 여러 화면에서 공유
  • UI 상태 + 서버 상태 혼합
  • 비교적 단순한 규칙
const useStore = create(set => ({
  count: 0,
  increase: () => set(s => ({ count: s.count + 1 })),
}));

장점:

  • boilerplate 적음
  • 부분 구독 가능
  • 러닝커브 낮음

🔹 Redux — “상태 자체가 도메인인 경우”

적합한 경우:

  • 상태 변경 규칙이 복잡
  • 이력 추적이 중요
  • 협업 규모 큼
  • 비즈니스 규칙이 명확
 
이 앱의 핵심은 “상태 흐름”이다

이런 프로젝트에서만 의미가 있다.

👉 Redux는 UI 편의 도구가 아니다
👉 아키텍처 도구다


5️⃣ 전역 상태가 늘어날수록 디버깅이 어려워지는 이유

이건 감각 문제가 아니라 구조적 이유다.

① 변경 지점이 분산된다

A 컴포넌트
B 컴포넌트
C 비동기 로직
D effect

👉 누가 언제 바꿨는지 추적이 어려움


② 렌더링 원인이 숨겨진다

// 화면은 다시 그려졌는데
// props도 안 바뀌었고
// state도 안 바뀐 것처럼 보인다

원인은?

👉 전역 상태 변경


③ 생명주기가 사라진다

로컬 상태라면:

  • 마운트 → 생성
  • 언마운트 → 제거

전역 상태는?

  • 앱 시작 → 생성
  • 앱 종료 → 제거

👉 언제 초기화해야 할지 별도 규칙이 필요


6️⃣ 실무에서 쓰는 판단 흐름 (이 순서로만 가라) 범위, 수명

상태를 만들 때 이 질문을 위에서부터 던진다.

  1. 이 컴포넌트만 쓰나? → 로컬
  2. 이 페이지에서만 쓰나? → 페이지 상위
  3. 여러 페이지가 쓰나? → 전역 후보
  4. 앱 핵심 규칙인가? (전역 + 규칙) → Redux 고려
  5. 단순 공유인가?  (전역 + 단순공유)  → Context / Zustand

👉 전역은 3번 이후에만 등장한다


7️⃣ 이 문장 하나로 끝낸다

이 글의 핵심은 이 문장이다.

전역 상태는
“편해서 쓰는 것”이 아니라
“안 쓰면 구조가 깨질 때만” 쓰는 것이다

전역 상태는

  • 설계가 끝난 뒤 쓰는 도구이지
  • 설계를 대신해주는 도구가 아니다.

다음 글에서는 이걸 이어서 간다.

👉 “Context는 왜 상태 관리 도구가 아닌가”

  • Context의 진짜 역할
  • 왜 남용하면 성능이 무너지는지
  • 상태 관리로 착각하게 만드는 이유

여기까지 왔으면
React를 상태 관리 라이브러리 모음이 아니라
상태를 배치하는 사고 체계로 보기 시작한 거다.

댓글