티스토리 뷰

 

프론트엔드 개발자라면 누구나 한 번쯤 "상태 관리를 위해 무엇을 써야 할까?"라는 고민에 빠집니다. 특히 React 생태계에서 Context APIRedux는 가장 자주 비교되는 대상이죠.

과거에는 "무조건 Redux"라는 분위기가 지배적이었지만, React 16.3 버전에서 Context API가 개선된 이후 흐름이 바뀌었습니다. 이제는 도구의 우열을 가리기보다, 우리 서비스의 복잡도성능 요구사항에 맞는 최적의 도구를 선택하는 눈이 필요합니다.


1. 핵심 개념 설명 (Deep Dive)

Context API: 데이터의 고속도로

Context API는 React에 내장된 기능으로, **'Prop Drilling'(수많은 컴포넌트를 거쳐 데이터를 전달하는 현상)**을 해결하기 위해 탄생했습니다. 특정 데이터를 '전역'으로 선언하고, 필요한 컴포넌트에서 직접 꺼내 쓸 수 있게 해줍니다.

  • 비유: Context API는 건물 각 층에 연결된 **'중앙 급수 시스템'**과 같습니다. 중간 층을 거칠 필요 없이 수도꼭지만 틀면 바로 물(데이터)이 나옵니다.

Redux: 엄격한 관리 체계를 가진 은행

Redux는 Flux 아키텍처를 기반으로 한 외부 라이브러리입니다. 단순히 데이터를 공유하는 것을 넘어, 데이터가 '언제, 어디서, 어떻게' 변경되었는지 추적하는 데 최적화되어 있습니다.

  • 비유: Redux는 **'철저한 기록 시스템을 갖춘 은행'**입니다. 돈(상태)을 찾으려면 전표(Action)를 작성해야 하고, 행원(Reducer)이 장부(Store)를 업데이트해야 합니다. 이 모든 과정은 기록(Log)으로 남습니다.

2. 풍부한 실전 예제 (Hands-on)

단순한 카운터 예제 대신, 실제 커머스 앱에서 흔히 발생하는 **'장바구니(Cart) 시스템'**을 예로 들어보겠습니다.

Case 1: Context API를 활용한 가벼운 상태 공유

소규모 프로젝트나 사용자 테마, 로그인 정보처럼 변경 빈도가 낮을 때 유리합니다.

JavaScript
 
import React, { createContext, useContext, useState } from 'react';

// 1. 컨텍스트 생성
const CartContext = createContext();

export const CartProvider = ({ children }) => {
  const [items, setItems] = useState([]);

  // 장바구니 추가 로직
  const addToCart = (product) => {
    setItems((prev) => [...prev, product]);
  };

  return (
    <CartContext.Provider value={{ items, addToCart }}>
      {children}
    </CartContext.Provider>
  );
};

// 2. 커스텀 훅으로 간편하게 사용
export const useCart = () => useContext(CartContext);

Case 2: Redux Toolkit(RTK)을 활용한 체계적 관리

복잡한 비즈니스 로직, API 연동, 상태 변경 추적이 중요한 대규모 앱에 적합합니다.

JavaScript
 
import { createSlice, configureStore } from '@reduxjs/toolkit';

// 1. Slice 생성 (Action + Reducer 통합)
const cartSlice = createSlice({
  name: 'cart',
  initialState: { items: [], totalQuantity: 0 },
  reducers: {
    addItem(state, action) {
      const newItem = action.payload;
      state.items.push(newItem);
      state.totalQuantity++; // Immer 라이브러리 내장으로 '가변' 로직처럼 작성 가능
    },
  },
});

// 2. Store 설정
export const store = configureStore({
  reducer: { cart: cartSlice.reducer },
});

export const { addItem } = cartSlice.actions;

⚠️ Troubleshooting: Context API의 성능 함정

Context API를 사용할 때 가장 많이 하는 실수는 **'객체 형태의 value'**를 그대로 넘기는 것입니다.

  • 문제: items만 변경되어도 addToCart 함수를 사용하는 모든 컴포넌트가 리렌더링될 수 있습니다.
  • 해결: useMemo로 값을 최적화하거나, 상태(State)와 변경 함수(Dispatch)를 별도의 Context로 분리하세요.

3. 장점 및 단점 (Trade-offs)

비교 항목 Context API Redux (RTK)
설치 비용 내장 기능 (추가 용량 0) 외부 라이브러리 설치 필요
학습 곡선 낮음 (React 훅만 알면 됨) 높음 (Action, Reducer, Store 개념)
성능 최적화 대규모 업데이트 시 리렌더링 관리 어려움 Slice 단위 선택적 리렌더링 우수
디버깅 어려움 (상태 변화 추적 불가) 강력함 (Redux DevTools 활용)
미들웨어 지원하지 않음 Thunk, Saga 등 비동기 처리 강력

4. 결론 및 요약: 당신의 선택은?

결국 선택의 기준은 **"데이터가 얼마나 자주 바뀌는가?"**와 **"애플리케이션의 규모가 어느 정도인가?"**에 달려 있습니다.

  1. Context API를 선택하세요:
    • 다크모드 설정, 다국어 처리(i18n), 로그인 사용자 세션 등 변경이 잦지 않은 데이터를 다룰 때.
    • 외부 라이브러리 의존성을 줄이고 가벼운 앱을 유지하고 싶을 때.
  2. Redux를 선택하세요:
    • 상태 업데이트 로직이 복잡하고(예: 복합적인 필터링 시스템), 여러 곳에서 이 상태를 동시에 참조할 때.
    • 비동기 작업(API 호출)이 많고, 개발자 도구를 통해 상태 변화를 시각적으로 추적하며 디버깅하고 싶을 때.

현명한 시니어라면 **'도구에 매몰되지 않는 것'**이 중요합니다. 때로는 useState와 useReducer 조합만으로도 충분할 수 있고, 전역 상태가 아닌 React QuerySWR 같은 서버 상태 관리 도구로 해결되는 경우도 많으니까요.

지금 개발 중인 프로젝트의 데이터 흐름도를 그려보세요. 그 화살표가 너무 복잡하게 얽혀 있다면, 그때가 바로 Redux라는 강력한 관리자를 영입할 시점입니다.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함