이번주 내내 내 머릿속을 지배한 Context API..
이제 블로깅을 하고 잠시만이라도 보내주자...🥲
Context API
Context API는 리액트에서 제공하는 전역 상태 관리 도구다.
애플리케이션이 복잡해지고 너무 많은 상태가 있으면 상태 관리가 어려워지고
과도한 props drilling, 즉 후손 컴포넌트로 props 넘겨주기가 나타날 수 있다.
Context API를 사용하면 전역에서 상태를 관리하며 필요한 컴포넌트에만 상태를 공급해 줄 수 있다.
다만 컨텍스트는 꼭 필요할 때만 써야 한다. 컨텍스트를 사용하면 컴포넌트의 재사용성이 떨어질 수 있다.
오직 props drilling을 막기 위해서라면 컴포넌트 합성이 더 좋을 수도 있다고 한다.
Context API 사용하기
컨텍스트는 만들고-제공하고-사용하고 이렇게 세 단계를 기억하면 된다.
유데미 강의의 음식 주문 앱 예제를 통해서 Context API를 실습해보자.
이렇게 생긴 페이지로, 아래 메뉴란에서 수량을 선택하고 추가 버튼을 누르면
상단 오른쪽에 있는 카트에 수량이 표시되며 카트 모달창을 통해 카트 내용과 가격을 확인할 수 있다.
메뉴의 수량과 가격등은 현 페이지의 메뉴 페이지에서 받아서 상단 오른쪽 카트 아이콘에서 사용해야 하고
카트 모달창에서도 사용해야 하기 때문에 여러 컴포넌트에서 동일한 상태를 필요로 한다.
Context API를 통해서 props drilling을 만들지 않고 전역에서 상태를 사용해 보자.
만들기: React.createContext
React.createContext를 통해 컨텍스트 객체를 생성한다.
여기에 전역에서 관리해 줄 상태를 넣어주면 된다.
이때 상태는 그냥 상태의 초기값일 뿐이고 적절한 Provider를 찾지 못했을 때만 쓰인다.
초기값을 설정해 준 뒤에는 상태를 공급해 줄 부모 컴포넌트에서 상태를 동적으로 변경해줘야 한다.
카트에서 사용할 상태는 네 가지, 아이템이 담긴 배열과 아이템 가격,
카트에 아이템을 추가하고 빼는 함수 두 개다.
import React from "react";
const CartContext = React.createContext({
items: [],
totalAmount: 0,
addItem: (item) => {},
removeItem: (id) => {},
});
export default CartContext;
이처럼 사용할 상태를 컨텍스트 객체에 담아 주고 export 해주면 일단 생성은 끝!
공급하기: Context.Provider
이제 상태를 만들었으니 상태를 동적으로 변경해줄 부모 컴포넌트로 가서 Provider를 만들어준다.
<Context.Provider>로 상태를 필요로 하는 컴포넌트들의 부모 컴포넌트를 감싸 주면
value 속성에 들어있는 컨텍스트가 바뀔 때 그 컨텍스트의 상태를 사용하는 컴포넌트들이 리렌더링 된다.
이번 예제에서는 컨텍스트 객체 생성과 컨텍스트 공급을 별도로 해줬다.
import CartContext from "./cart-context";
const CartProvider = (props) => {
const addItemToCartHandler = (item) => {};
const removeItemFromCartHandler = (id) => {};
const cartContext = {
items: [],
totalAmout: 0,
addItem: addItemToCartHandler,
removeItem: removeItemFromCartHandler,
};
return (
<CartContext.Provider value={cartContext}> //요기가 포인트!
{props.children}
</CartContext.Provider>
);
};
export default CartProvider;
CartProvider라는 (이름만 provider인) 새로운 컴포넌트를 만든 뒤
진짜 Provider인 <CartContext.Provider>를 리턴해준다.
얘는 {props.children}을 받고 그 안에 있는 컴포넌트들에게 상태 변경 알리미 역할을 한다.
사용하기: useContext
이제 상태를 사용할 컴포넌트들로 가서 useContext 훅으로 컨텍스트 객체를 불러온다.
import { useContext } from "react";
import CartContext from "../../store/cart-context";
const HeaderCartButton = (props) => {
const cartCtx = useContext(CartContext);//CartContext 불러오기
const numberOfCartItems = cartCtx.items.length; //item 배열의 길이를 가져온다
return (
<button className={classes.button} onClick={props.onClick}>
<span className={classes.icon}>
<CartIcon />
</span>
<span>Your Cart</span>
<span className={classes.badge}>{numberOfCartItems}</span> //그리고 여기서 써줌
</button>
);
};
export default HeaderCartButton;
컨텍스트 객체에 들어있는 items 배열을 꺼내오고 그 길이를 카트 아이콘에 넣어주었다.
이렇게 하면 일단 카트 아이콘에서 items 상태를 사용할 수 있게 만들기는 하였으나..
이 애플리케이션의 "찐"은 카트 모달창에 있으니.. 이 아이를 위해서는 useReducer를 쓸 것이다.
useReducer와 컨텍스트를 결합해서 쓰는 방법은.. 다음에 알아보자..ㅎㅎ
Context.Consumer를 쓰는 법도.. 다음에 알아보자🙃
'React' 카테고리의 다른 글
[React] useRef (0) | 2023.04.12 |
---|---|
[React] useReducer (2) | 2023.04.07 |
[React] useEffect 사용하기 (0) | 2023.03.31 |
[React] state, props (3) | 2023.03.26 |
[React] React Router 사용해 SPA 만들기 (0) | 2023.03.23 |