코드도보통지

3관문. State Colocation in Context

관문 3 / 7

앱 루트가 아닌 가장 가까운 공통 조상에 Provider를 배치하여 영향 범위를 최소화하라.

📖 이론 비급

Sub-tree Context: 부분 전역 상태

모든 Context를 루트에 두는 것은 안티패턴이다. 장바구니 상태는 쇼핑 페이지 트리에만, 폼 상태는 해당 폼 컴포넌트에만 필요하다.

원칙: Context도 일반 상태처럼 Colocation을 적용하라. 루트에 두면 전체가 영향받지만, 공통 조상에 두면 해당 서브트리만 영향받는다. 전역 상태 라이브러리가 필요한지 먼저 Context Colocation을 시도하라.

⚔️ 수련 코드

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

// 문제: ShopCart 상태가 앱 루트에 있어 Header도 불필요하게 리렌더된다
const CartContext = createContext();

export function useCart() {
  return useContext(CartContext);
}

// TODO: CartProvider를 ShopPage 안으로 이동하여
// Header가 cart 변경에 영향받지 않도록 하라

export default function App() {
  const [items, setItems] = useState([]);
  return (
    <CartContext.Provider value={{ items, addItem: (item) => setItems(prev => [...prev, item]) }}>
      <Header />
      <ShopPage />
    </CartContext.Provider>
  );
}

function Header() {
  console.log('Header 렌더');
  return <nav>헤더</nav>;
}

function ShopPage() {
  const { items, addItem } = useCart();
  return (
    <div>
      <button onClick={() => addItem({ id: Date.now() })}>상품 추가</button>
      <p>장바구니: {items.length}개</p>
    </div>
  );
}