본문 바로가기
🌐 Frontend/⚛️ React

나는 왜 전역 상태관리를 만들게 되었는가 (반복 호출, 버벅임, 유지 비용 문제를 겪으며 깨달은 구조 설계)

by itstory(Booho) 2026. 3. 1.
반응형

나는 왜 전역 상태관리를 만들게 되었는가 (반복 호출, 버벅임, 유지 비용 문제를 겪으며 깨달은 구조 설계)

전역 상태관리는 “멋있어 보여서” 도입하는 기술이 아닙니다. 대부분은 개발을 하다가 반복 호출, 버벅임, 유지 비용 증가를 체감한 후에 “구조를 바꿔야겠다”는 결론으로 이어집니다.

이 글은 전역 상태가 필요한 상황을 실무에서 실제로 자주 겪는 패턴으로 설명하고, 바로 적용할 수 있는 예제 코드주의사항까지 포함합니다.


1. 전역 상태관리의 출발점: “같은 걸 계속 호출하고 있다”

처음에는 페이지나 컴포넌트마다 필요한 데이터를 개별 호출합니다. 이 방식은 구현이 빠르지만, 구조가 커질수록 아래 문제가 쌓입니다.

  • 같은 API를 여러 컴포넌트가 동시에 호출한다
  • 화면 진입마다 같은 데이터를 다시 가져온다
  • 로딩 UI가 여러 군데서 중복된다
  • 사용자는 “버벅임”을 체감한다

그리고 운영 단계에서는 이게 비용으로 이어집니다.

  • 중복 요청 → 트래픽 증가
  • 트래픽 증가 → 서버/DB 부하 증가
  • 부하 증가 → 인프라 확장/유지 비용 증가

핵심 : “전역 상태”는 편의 기능이 아니라 중복 호출을 줄여 성능과 비용을 관리하는 구조입니다.


2. “그럼 공통 함수로 묶으면 되지 않나?”가 왜 한계가 있는가

초보 단계에서는 보통 이렇게 해결합니다.

  • fetch 함수를 하나로 만들기
  • API 호출을 유틸로 분리하기

이건 좋은 습관이지만, 문제를 완전히 해결하지는 못합니다.

  • 유틸로 묶어도 “호출 위치”가 여러 곳이면 요청은 여전히 여러 번 발생
  • 상태(로딩/에러/데이터)를 각 컴포넌트가 따로 관리 → 중복
  • 데이터 동기화가 어려움 → 어떤 컴포넌트는 최신, 어떤 컴포넌트는 이전 값

즉, 유틸은 “코드 중복”만 줄이고, 전역 상태는 “호출/상태/동기화”까지 줄이는 방향입니다.


3. 전역 상태가 적합한 데이터의 조건(실무 기준)

아래 조건을 만족하면 전역으로 올릴 가능성이 높습니다.

  • 앱 전역에서 여러 컴포넌트가 참조한다
  • 자주 변하지 않거나(설정/세션/권한), 변하더라도 “중앙에서 일관되게” 바뀌어야 한다
  • 중복 호출 시 비용(속도/트래픽/서버 부하)이 발생한다

대표 예시는 다음과 같습니다.

  • 로그인 상태/권한
  • 사용자 프로필(이름/권한 등)
  • 테마(다크모드), 언어 설정, 공통 UI 설정
  • 앱 초기 로딩 시 필요한 공통 데이터

4. 아주 작은 전역 상태 예제(“중복 호출 제거”의 핵심을 보여주는 버전)

아래는 “공통 데이터를 한 번만 로드하고, 어디서든 재사용”하는 가장 단순한 형태입니다.

4-1) 전역 컨텍스트 만들기

import React, { createContext, useContext, useEffect, useMemo, useState } from "react";

type AppConfig = {
  theme: "light" | "dark";
  region: string;
};

type AppConfigState = {
  config: AppConfig | null;
  isLoading: boolean;
  error: string | null;
  refresh: () => Promise<void>;
};

const AppConfigContext = createContext<AppConfigState | null>(null);

export function AppConfigProvider({ children }: { children: React.ReactNode }) {
  const [config, setConfig] = useState<AppConfig | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  async function load() {
    setIsLoading(true);
    setError(null);
    try {
      // 예시: 공통 설정 API (프로젝트에 맞게 교체)
      const res = await fetch("/api/app-config");
      if (!res.ok) throw new Error("Failed to load config");
      const data = (await res.json()) as AppConfig;
      setConfig(data);
    } catch (e: any) {
      setError(e?.message ?? "Unknown error");
      setConfig(null);
    } finally {
      setIsLoading(false);
    }
  }

  useEffect(() => {
    // 앱 시작 시 단 1회 로드
    load();
  }, []);

  const value = useMemo(
    () => ({ config, isLoading, error, refresh: load }),
    [config, isLoading, error]
  );

  return (
    <AppConfigContext.Provider value={value}>
      {children}
    </AppConfigContext.Provider>
  );
}

export function useAppConfig() {
  const ctx = useContext(AppConfigContext);
  if (!ctx) throw new Error("useAppConfig must be used within AppConfigProvider");
  return ctx;
}

4-2) 아무 컴포넌트에서나 사용하기

import React from "react";
import { useAppConfig } from "./AppConfigProvider";

export function Header() {
  const { config, isLoading, error } = useAppConfig();

  if (isLoading) return <div>로딩 중...</div>;
  if (error) return <div>에러: {error}</div>;
  if (!config) return null;

  return (
    <div>
      현재 테마: {config.theme} / 지역: {config.region}
    </div>
  );
}

5. 적용 방법(어디에 감싸야 하나?)

전역 상태 Provider는 일반적으로 앱 최상단에 둡니다. 그래야 모든 컴포넌트가 접근할 수 있습니다.

// 예시: React App 최상단
export default function AppRoot() {
  return (
    <AppConfigProvider>
      <App />
    </AppConfigProvider>
  );
}

Next.js(App Router)에서는 보통 layout.tsx(또는 Client Layout Wrapper)에서 감싸는 형태로 이어집니다. 이 부분은 3편에서 자세히 다룹니다.


6. 주의사항(이 부분이 없으면 실무 글이 아니다)

주의 1) 전역 상태는 “최소한”만

  • 모든 데이터를 전역으로 올리면 오히려 복잡해진다
  • “정말 여러 곳에서 필요하고, 중복 호출/중복 상태가 발생하는 것만” 전역으로

주의 2) Provider value 객체는 useMemo로 묶어라

Provider의 value가 렌더마다 새 객체가 되면 하위가 불필요하게 리렌더될 수 있습니다. 위 예제에서 useMemo를 사용한 이유입니다.

주의 3) 상태를 하나의 Provider에 다 때려 넣지 말아라

인증/설정/UI/캐시를 한 Provider에 몰아넣으면 value 변경이 잦아지고 리렌더 비용이 커집니다. 보통은 “역할별 Provider 분리”가 관리하기 쉽습니다.


마무리

전역 상태관리의 핵심은 “언제 도입하느냐”입니다. 중복 호출이 보이고, 버벅임이 체감되고, 유지 비용이 증가하는 순간, 그때 전역 상태는 기술이 아니라 구조를 정리하는 선택이 됩니다.

다음 글에서는 Context API를 “실무에서 쓰기 좋은 형태”로 설계하는 방법을 더 깊게 다룹니다. (Provider 분리, 타입 설계, 업데이트 패턴 등)

반응형