Reducer

jinabbb·2022년 4월 13일
0

기존 Context를 이용해서 State를 관리할 때는

CartItem이 바뀌면 useEffect훅을 이용해 CartTotal,CartCount도 바꿔줬다

{cartItems:[] , cartCount:0 , cartTotal:0}

useEffect가 아닌 Action을 이용한다

{type: STRING , payload: anything}

{type: “ADD_ITEM_TO_CART” , payload: {...cartItem}}

기본 형태

const [state, dispatch] = useReducer(reducer, initialState);

useState,useEffect로 state를 관리했던 cartContext를 useRedcuer로 migration하면서 사용법을 비교해보자

기존 CartContext


export const CartContext = createContext({
	isCartOpen: false,
	setIsCartOpen: () => {},
	cartItems: [],
	addItemToCart: () => {},
	cartCount: 0,
	removeItemFromCart: () => {},
	clearItemFromCart: () => {},
	cartTotal: 0,
});

export const CartProvider = ({ children }) => {
	const [isCartOpen, setIsCartOpen] = useState(false);
	const [cartItems, setCartItems] = useState([]);
	const [cartCount, setCartCount] = useState(0);
	const [cartTotal, setCartTotal] = useState(0);

	useEffect(() => {
		const newCount = cartItems.reduce(
			(total, cartItem) => total + cartItem.quantity,
			0
		);
		setCartCount(newCount);
	}, [cartItems]);

	useEffect(() => {
		const newTotal = cartItems.reduce(
			(total, cartItem) => total + cartItem.quantity * cartItem.price,
			0
		);
		setCartTotal(newTotal);
	}, [cartItems]);

	const addItemToCart = (productToAdd) => {
		setCartItems(addCartItem(cartItems, productToAdd));
	};

	const removeItemFromCart = (cartItemToRemove) => {
		setCartItems(removeCartItem(cartItems, cartItemToRemove));
	};

	const clearItemFromCart = (cartItemToClear) => {
		setCartItems(clearCartItem(cartItems, cartItemToClear));
	};

	const value = {
		isCartOpen,
		setIsCartOpen,
		cartItems,
		addItemToCart,
		cartCount,
		removeItemFromCart,
		clearItemFromCart,
		cartTotal,
	};
	return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
};

cartImems가 바뀔때 cartCount와 cartTotal을 바꿔준다. =⇒ state변화가 자주 일어난다.

useReducer 사용후


export const CART_ACTION_TYPES = {
	SET_CART_ITEM: 'SET_CART_ITEM',
	SET_IS_CART_OPEN: 'SET_IS_CART_OPEN',
};

export const cartReducer = (state, action) => {
	const { type, payload } = action;

	switch (type) {
		case CART_ACTION_TYPES.SET_CART_ITEM:
			return {
				...state,
				...payload,
			};
		case CART_ACTION_TYPES.SET_IS_CART_OPEN:
			return {
				...state,
				isCartOpen: payload,
			};
		default:
			throw new Error(`Unhandled type ${type}`);
	}
};
const INITIAL_STATE = {
	isCartOpen: false,
	cartItems: [],
	cartCount: 0,
	cartTotal: 0,
};
export const CartProvider = ({ children }) => {
	const [{ cartItems, isCartOpen, cartTotal, cartCount }, dispatch] =
		useReducer(cartReducer, INITIAL_STATE);
	const updateCartItemsReducer = (newCartItems) => {
		const newCount = cartItems.reduce(
			(total, cartItem) => total + cartItem.quantity,
			0
		);
		const newTotal = cartItems.reduce(
			(total, cartItem) => total + cartItem.quantity * cartItem.price,
			0
		);
		dispatch({
			type: CART_ACTION_TYPES.SET_CART_ITEM,
			payload: {
				cartItems: newCartItems,
				cartCount: newCount,
				cartTotal: newTotal,
			},
		});
	};
	const addItemToCart = (productToAdd) => {
		const newCartItems = addCartItem(cartItems, productToAdd);
		updateCartItemsReducer(newCartItems);
	};

	const removeItemFromCart = (cartItemToRemove) => {
		const newCartItems = removeCartItem(cartItems, cartItemToRemove);
		updateCartItemsReducer(newCartItems);
	};

	const clearItemFromCart = (cartItemToClear) => {
		const newCartItems = clearCartItem(cartItems, cartItemToClear);
		updateCartItemsReducer(newCartItems);
	};
	const setIsCartOpen = (bool) => {
		dispatch({ type: CART_ACTION_TYPES.SET_IS_CART_OPEN ,payload:bool});
	};
	const value = {
		isCartOpen,
		setIsCartOpen,
		cartItems,
		addItemToCart,
		cartCount,
		removeItemFromCart,
		clearItemFromCart,
		cartTotal,
	};
	return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
};

ACTION_TYPES로 ACTION들을 정의해주고

cartReducer 함수는 기존state와 action객체로 새로운 state를 반환한다.

cartItem이 바뀔 때 모두 같은 updateCarrtItemsReducer함수 하나로 state를 업데이트 해준다.

setter함수를 한번에 여러번 호출할 구조가 생기면 useRedcuer를 사용하는것이 바람직해 보인다.

profile
개발

0개의 댓글