Frontend Study
React #14 _ 다시 한번 useContext
jimmmy_jin
2025. 1. 3. 12:26
React의 useContext로 상태를 공유하는 효율적인 방법: Cart 예제
React 개발을 하다 보면 컴포넌트 간에 데이터를 공유해야 하는 상황이 자주 발생한다. 특히, 쇼핑 카트와 같은 기능에서는 여러 컴포넌트에서 동일한 상태(예: 장바구니 아이템 목록, 총 금액)를 참조하거나 수정해야 할 때가 많다. 이런 상황에서 **useContext**는 간단하고 효율적인 해결책을 제공한다.
1. useContext란 무엇인가?
useContext는 React의 Context API를 활용하여 전역 상태를 쉽게 사용할 수 있도록 도와주는 Hook이다.
주요 특징
- 부모 컴포넌트에서 데이터를 자식 컴포넌트로 전달할 때 Props Drilling을 방지한다.
- 전역 상태를 관리하는 Context를 생성하고, 하위 컴포넌트에서 해당 상태를 쉽게 소비할 수 있다.
- 상태나 로직을 필요한 컴포넌트에서만 접근 가능하다.
2. 기본적인 사용법
1) Context 생성
createContext를 사용하여 Context를 생성한다.
import React, { createContext } from "react";
const CartContext = createContext(); // Cart 상태를 위한 Context 생성
2) Context Provider
Provider 컴포넌트를 통해 상태와 값을 하위 컴포넌트에 전달한다.
export function CartProvider({ children }) {
const cart = []; // 장바구니 초기 상태
const addItemToCart = (item) => {
cart.push(item); // 장바구니에 아이템 추가 (예제용)
};
return (
<CartContext.Provider value={{ cart, addItemToCart }}>
{children}
</CartContext.Provider>
);
}
3) Context Consumer
useContext를 사용하여 Context에 저장된 상태와 함수를 소비한다.
import { useContext } from "react";
import { CartContext } from "./CartProvider";
export function CartDisplay() {
const { cart, addItemToCart } = useContext(CartContext);
return (
<div>
<h2>Your Cart</h2>
<ul>
{cart.map((item, index) => (
<li key={index}>{item.name}</li>
))}
</ul>
</div>
);
}
3. 쇼핑 카트 예제
Cart 상태 관리
아래 코드는 useContext를 사용하여 쇼핑 카트 상태를 관리하는 예제이다.
CartProvider.js
import React, { createContext, useState } from "react";
const CartContext = createContext();
export function CartProvider({ children }) {
const [cart, setCart] = useState([]);
const addItemToCart = (item) => {
setCart((prevCart) => [...prevCart, item]);
};
const removeItemFromCart = (id) => {
setCart((prevCart) => prevCart.filter((item) => item.id !== id));
};
return (
<CartContext.Provider value={{ cart, addItemToCart, removeItemFromCart }}>
{children}
</CartContext.Provider>
);
}
export function useCart() {
return useContext(CartContext);
}
CartDisplay.js
import React from "react";
import { useCart } from "./CartProvider";
export function CartDisplay() {
const { cart, removeItemFromCart } = useCart();
return (
<div>
<h2>Your Cart</h2>
<ul>
{cart.map((item) => (
<li key={item.id}>
{item.name} - ${item.price}
<button onClick={() => removeItemFromCart(item.id)}>Remove</button>
</li>
))}
</ul>
</div>
);
}
ProductList.js
import React from "react";
import { useCart } from "./CartProvider";
export function ProductList() {
const { addItemToCart } = useCart();
const products = [
{ id: 1, name: "Apple", price: 2 },
{ id: 2, name: "Banana", price: 1 },
{ id: 3, name: "Cherry", price: 3 },
];
return (
<div>
<h2>Product List</h2>
<ul>
{products.map((product) => (
<li key={product.id}>
{product.name} - ${product.price}
<button onClick={() => addItemToCart(product)}>Add to Cart</button>
</li>
))}
</ul>
</div>
);
}
App.js
import React from "react";
import { CartProvider } from "./CartProvider";
import { ProductList } from "./ProductList";
import { CartDisplay } from "./CartDisplay";
export default function App() {
return (
<CartProvider>
<ProductList />
<CartDisplay />
</CartProvider>
);
}
4. useContext와 useReducer 비교
useContext는 전역적으로 상태를 공유할 때 매우 편리하지만, 상태 관리가 복잡해지는 경우 **useReducer**와 조합하면 더 강력한 상태 관리가 가능하다.
- 단순한 상태 공유: useContext로 충분하다.
- 복잡한 로직 및 여러 액션: useContext + useReducer 조합 추천.
5. useContext의 장점
- Props Drilling 방지
여러 단계의 자식 컴포넌트에 Props를 전달할 필요가 없다. - 코드 간결화
상태와 로직을 전역으로 관리하여 중복 코드를 줄일 수 있다. - 유연성
필요에 따라 언제든지 새로운 상태와 로직을 추가하거나 수정할 수 있다.
6. 마무리
React의 useContext는 상태를 여러 컴포넌트에서 공유할 때 매우 유용한 도구다. 특히 쇼핑 카트처럼 상태가 여러 컴포넌트에서 필요할 때 Props Drilling을 방지하고 코드를 깔끔하게 유지할 수 있다.