Reducer는 현재 상태와 액션을 받아서 새로운 상태를 반환하는 순수함수이다. Redux에서 상태의 변화를 처리하며 불변성을 유지하면서 상태를 업데이트해야 한다.
const cartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
clearCart: (state) => {
state.cartItems = [];
},
},
});
export const { clearCart } = cartSlice.actions;
clearCart 라는 장바구니를 비우는 리듀서를 추가
Action은 어떤 변화가 일어났는지 설명하는 객체이다. 애플리케이션에서 어떠한이벤트가 발생했음을 나타낸다.
일반적으로 type 속성을 가지고 있으며, 이를 통해 어떤 종류의 액션이 발생했는지를 식별한다. 그 외에 필요한 정보는 payload라는 속성을 통해 전달한다.
const ACTION_TYPE = 'ACTION_TYPE';
const actionCreator = (payload) => {
return { type: ACTION_TYPE, payload: payload };
};
ACTION_TYPE 은 액션의 타입을 나타내는 문자열 상수이다. 액션 객체에서 어떤 종류의 액션이 발생했는지 식별하는데 사용된다.
actionCreator는 액션을 생성하는 함수로 액션 객체를 반환한다
💡 Redux-Toolkit애서 Reducer와 Action
원래 Redux에서는 Action과 Reducer를 개별적으로 분리하여 사용하지만 Redux-Toolkit에서는 createSlice를 사용하여 reducer와 action을 함께 정의한다.
코드가 간결해지고 유지보수성을 향상시킨다.
Redux에서 액션을 발생시켜 리듀서에게 전달하는 함수이다. Redux 스토어의 메서드 중 하나로 애플리케이션의 상태를 업데이트하는데 사용된다.
import React from 'react';
import CartItem from './CartItem';
import { removeItem } from '../features/cart/cartSlice';
import { useDispatch, useSelector } from 'react-redux';
const CartContainer = () => {
const dispatch = useDispatch();
return (
<button
className='btn clear-btn'
onClick={() => {
dispatch(clearCart());
}}
>
clear cart
</button>
);
};
삭제, 증가, 감소 기능을 Redux를 이용하여 만들어본다.
import { createSlice } from "@reduxjs/toolkit";
import cartItems from "../../cartItems";
const initialState = {
cartItems : cartItems,
amount : 4,
total : 0,
isLoading : true
}
const cartSlice = createSlice({
name : 'cart',
initialState,
reducers: {
clearCart: (state) => {
state.cartItems = [];
},
removeItem : (state, action) => {
const itemId = action.payload;
state.cartItems = state.cartItems.filter((item) => item.id !== itemId);
},
increase: (state, { payload }) => {
const cartItem = state.cartItems.find((item) => item.id === payload.id)
cartItem.amount = cartItem.amount + 1
},
decrease: (state, { payload }) => {
const cartItem = state.cartItems.find((item) => item.id === payload.id)
cartItem.amount = cartItem.amount - 1
},
}
})
export const { clearCart, removeItem, increase, decrease } = cartSlice.actions;
export default cartSlice.reducer;
import React from 'react'
import { ChevronDown, ChevronUp } from '../icons'
import { removeItem, increase, decrease } from '../features/cart/cartSlice';
import { useDispatch } from 'react-redux';
const CartItem = ({id, img, title, price, amount}) => {
const dispatch = useDispatch();
return (
<article className='cart-item'>
<img src={img} alt={title}/>
<div>
<h4>{title}</h4>
<h4 className="item-price">${price}</h4>
<button className='remove-btn' onClick={() => {
dispatch(removeItem(id));
}}>삭제</button>
</div>
<div>
<button className='amount-btn' onClick={() => {
dispatch(increase({ id }))
}}>
<ChevronUp/>
</button>
<p className='amount'>{amount}</p>
<button className='amount-btn' onClick={() => {
dispatch(decrease({ id }))
}}>
<ChevronDown/>
</button>
</div>
</article>
)
}
export default CartItem
onClick 이벤트로 삭제 증가 감소를 Redux를 통해 상태관리 하도록 하였다.
App.js
import { useDispatch, useSelector } from "react-redux";
import CartContainer from "./components/CartContainer";
import Navbar from "./components/Navbar";
import { useEffect } from "react";
import { calculateTotals } from "./features/cart/cartSlice";
function App() {
const { cartItems } = useSelector((state) => state.cart);
const dispatch = useDispatch();
useEffect(() => {
dispatch(calculateTotals())
},[cartItems])
return (
<main>
<Navbar/>
<CartContainer/>
</main>
)
}
export default App;
carItems이 변경되면 자동으로 계산해줄 수 있도록 설정
calculateTotals: (state) => {
let amount = 0;
let total = 0;
state.cartItems.forEach((item) => {
amount += item.amount;
total += item.amount * item.price;
});
state.amount = amount;
state.total = total;
},
리듀서 추가