Context Outsourcing(아웃소싱) & Provider 컴포넌트 분리 정리

장효정·2025년 12월 15일

Udemy React 강의 172번 정리

문제 상황 : App 컴포넌트가 너무 비대해짐

지금까지 App 컴포넌트에서 :

  • 장바구니 state 관리 (useState)
  • 아이템 추가 / 수량 변경 함수들
  • Context에 전달할 value 객체 생성
  • <CartContext.Provider value={...}> 설정

즉, Context + State + 로직이 전부 App에 몰려 있음.
이렇게 되면 App 컴포넌트가 점점 거대해지고, Context가 여러 개 생기면 App이 더 복잡해진다.
즉, 루트 컴포넌트는 깔끔해야 한다는 원칙에 어긋남.

해결 : Context 전용 Provider 컴포넌트 만들기

Context + State + 관련 로직을 App이 아니라 Context Provider 컴포넌트로 옮기는 것이다.

즉, Context를 사용만 하는 쪽(App)과 Context를 관리하는 쪽(Provider 컴포넌트)를 분리하는 것.

shopping-cart-context의 역할

이제 Context 파일은 단순히 createContext만 하는 것이 아니라 (1) 장바구니 state, (2) 아이템 추가 / 수정 로직, (3) Context에 전달할 value 구성, (4) Provider 컴포넌트 렌더링 이 모든 걸 담당한다.

// src/store/shopping-cart-context.jsx

export default function CartContextProvider({ children }) {
  const [shoppingCart, setShoppingCart] = useState({
    items: [],
  });

  function handleAddItemToCart(id) {
    setShoppingCart(prevShoppingCart => {
      const updatedItems = [...prevShoppingCart.items];

      const existingCartItemIndex = updatedItems.findIndex(
        cartItem => cartItem.id === id
      );
      const existingCartItem = updatedItems[existingCartItemIndex];

      if (existingCartItem) {
        const updatedItem = {
          ...existingCartItem,
          quantity: existingCartItem.quantity + 1,
        };
        updatedItems[existingCartItemIndex] = updatedItem;
      } else {
        const product = DUMMY_PRODUCTS.find(product => product.id === id);
        updatedItems.push({
          id: id,
          name: product.title,
          price: product.price,
          quantity: 1,
        });
      }

      return {
        items: updatedItems,
      };
    });
  }

  function handleUpdateCartItemQuantity(productId, amount) {
    setShoppingCart(prevShoppingCart => {
      const updatedItems = [...prevShoppingCart.items];
      const updatedItemIndex = updatedItems.findIndex(
        item => item.id === productId
      );

      const updatedItem = {
        ...updatedItems[updatedItemIndex],
      };

      updatedItem.quantity += amount;

      if (updatedItem.quantity <= 0) {
        updatedItems.splice(updatedItemIndex, 1);
      } else {
        updatedItems[updatedItemIndex] = updatedItem;
      }

      return {
        items: updatedItems,
      };
    });
  }

  const ctxValue = {
    items: shoppingCart.items,
    addItemToCart: handleAddItemToCart,
    updateItemQuantity: handleUpdateCartItemQuantity,
  };

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

이 컴포넌트는 데이터와 로직을 감싸서 제공하는 역할을 하는 거지, UI를 만들기 위한 게 아님. 그래서 children을 받아서 그대로 감싸줌.


0개의 댓글