Section3 Unit4 [React] ์ํ ๊ด๋ฆฌ - ๊ณผ์ Cmarket Redux
โญ๏ธ ๊ณผ์ . Cmarket Redux
โ๏ธ Bare Minimum Requirement
โ Action, Reducer๋ฅผ ์ง์ ์์ฑํ๊ณ ํ ์คํธ ์ผ์ด์ค๋ฅผ ํต๊ณผํฉ๋๋ค.
โ๏ธ ๊ณผ์ ๊ตฌํ
๐ ๋ฆฌ๋์ค์ ๋ฐ์ดํฐ ํ๋ฆ Action → Dispatch → Reducer → Store
1. ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด์ผ ํ๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด, ๋ณ๊ฒฝ๋ ์ํ์ ๋ํ ์ ๋ณด๊ฐ ๋ด๊ธด Action ๊ฐ์ฒด๊ฐ ์์ฑ
2. Action ๊ฐ์ฒด๋ Dispatch ํจ์์ ์ธ์๋ก ์ ๋ฌ
3. Dispatch ํจ์๋ Action ๊ฐ์ฒด๋ฅผ Reducer ํจ์๋ก ์ ๋ฌ
4. Reducer ํจ์๋ Action ๊ฐ์ฒด์ ๊ฐ์ ํ์ธํ๊ณ , ๊ทธ ๊ฐ์ ๋ฐ๋ผ ์ ์ญ ์ํ ์ ์ฅ์ Store์ ์ํ๋ฅผ ๋ณ๊ฒฝ
5. ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด React๋ ํ๋ฉด์ ๋ค์ ๋ ๋๋ง
โจ handleClick, handleQuantityChange, handleDelete
์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ or ์๋ ๋ณ๊ฒฝ or ์ญ์ ๋ฒํผ์ ๋๋ ์ ๋
// ItemListContainer.js
// ๐ ์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ ๋ฒํผ์ ๋๋ ์ ๋
const handleClick = (item) => {
if (!cartItems.map((el) => el.itemId).includes(item.id)) {
//TODO: dispatch ํจ์๋ฅผ ํธ์ถํ์ฌ ์์ดํ
์ถ๊ฐ์ ๋ํ ์ก์
์ ์ ๋ฌํ์ธ์.
dispatch(addToCart(item.id))
dispatch(notify(`์ฅ๋ฐ๊ตฌ๋์ ${item.name}์ด(๊ฐ) ์ถ๊ฐ๋์์ต๋๋ค.`))
}
else {
dispatch(notify('์ด๋ฏธ ์ถ๊ฐ๋ ์ํ์
๋๋ค.'))
}
}
// ShoppingCart.js
// ๐ ์๋์ ๋ณ๊ฒฝํ ๋
const handleQuantityChange = (quantity, itemId) => {
//TODO: dispatch ํจ์๋ฅผ ํธ์ถํ์ฌ ์ก์
์ ์ ๋ฌํ์ธ์.
dispatch(setQuantity(itemId, quantity))
}
// ๐ ์ญ์ ๋ฒํผ์ ๋๋ ์ ๋
const handleDelete = (itemId) => {
setCheckedItems(checkedItems.filter((el) => el !== itemId))
//TODO: dispatch ํจ์๋ฅผ ํธ์ถํ์ฌ ์ก์
์ ์ ๋ฌํ์ธ์.
dispatch(removeFromCart(itemId))
}
// actions > index.js
// action types
export const ADD_TO_CART = "ADD_TO_CART";
export const REMOVE_FROM_CART = "REMOVE_FROM_CART";
export const SET_QUANTITY = "SET_QUANTITY";
// actions creator functions
export const addToCart = (itemId) => {
return {
type: ADD_TO_CART,
payload: {
quantity: 1,
itemId
}
}
}
export const removeFromCart = (itemId) => {
return {
//TODO
type: REMOVE_FROM_CART,
payload: {
itemId
}
}
}
export const setQuantity = (itemId, quantity) => {
return {
//TODO
type: SET_QUANTITY,
payload: {
itemId,
quantity
}
}
}
// reducers > itemReducer.js
import { REMOVE_FROM_CART, ADD_TO_CART, SET_QUANTITY } from "../actions/index";
import { initialState } from "./initialState";
const itemReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_TO_CART:
//TODO
return Object.assign({}, state, { cartItems: [...state.cartItems, action.payload] })
// Spread Syntax
// return { ...state, cartItems: [...state.cartItems, action.payload] }
case REMOVE_FROM_CART:
//TODO
const updatedItems = state.cartItems.filter((item) => item.itemId !== action.payload.itemId);
console.log(action.payload.itemId) // ์ญ์ ํ ์ ํ์ itemId
console.log("updatedItems", updatedItems) // ์ ํ์ด ์ญ์ ๋ ํ์ ๋ฆฌ์คํธ
return Object.assign({}, state, { cartItems: updatedItems })
case SET_QUANTITY:
let idx = state.cartItems.findIndex(el => el.itemId === action.payload.itemId);
//TODO
return Object.assign({}, state, {
cartItems: [...state.cartItems.slice(0, idx), action.payload, ...state.cartItems.slice(idx + 1)]
})
// Spread Syntax
/*
return {
...state,
cartItems: [...state.cartItems.slice(0, idx), action.payload, ...state.cartItems.slice(idx + 1)]
}
*/
// map
/*
return {
...state,
cartItems: state.cartItems.map((el, index) => index === idx ? action.payload : el)
}
*/
// map (idx ์ฌ์ฉ X)
/*
return {
...state,
cartItems: state.cartItems.map((el) => el.itemId === action.payload.itemId ? action.payload : el)
}
*/
default:
return state;
}
}
export default itemReducer;
Reducer์ Immutability(๋ถ๋ณ์ฑ)
Redux์ state ์ ๋ฐ์ดํธ๋ immutableํ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝํด์ผ ํ๊ธฐ ๋๋ฌธ์ Reducer ํจ์๋ฅผ ์์ฑ์ ์ฃผ์ํด์ผ ํ๋ค.
immutableํ ๋ฐฉ์์ผ๋ก state๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ํด์๋ Object.assign()
๋๋ spread syntax
๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
๐ ์ค๋์ ํ๊ณ
์ด๋ ๊ฒ ํ ์ฃผ๊ฐ ๋ฒ์จ ๋์ด ๋ฌ๋ค. ์ด๋ฒ ์ฃผ๋ ๋ฆฌ์กํธ๋ก custom component ๋ง๋ค๊ธฐ๋ถํฐ ๋ฆฌ๋์ค๊น์ง, ๋ฐฐ์์ผ ํ ๊ฒ๋ค๋ ๋ง์๊ณ , ๋ฐฐ์ธ ๊ฒ์ด ๋ง์ผ๋ ์ ๋ฆฌํด์ผ ํ ๋ถ๋ถ๋ ๋ง์๋ค. ๊พธ์คํ ์ต๊ด์ฒ๋ผ ํ๋ ๋ธ๋ก๊น ๋ ์ ๋๋ก ๋ชปํ๊ณ , ์์ง ๋ ธ์ ์ ๋ฆฌ๋ ์ ๋๋ก ๋ชปํด์ ์ฃผ๋ง๋์ ์ด์ฌํ ์ ๋ฆฌ๋ฅผ ํด๋ณผ ์๊ฐ์ด๋ค. ๋ถํธ์บ ํ TIL ๋ธ๋ก๊น ์ ์ฌ์ค ๋์ค์ ๋ฉด์ ์๋ฆฌ์์ ์ฑ์ค์ฑ์ ์กฐ๊ธ์ด๋๋ง ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์์ํ ์ด์ ๋ ์์๋๋ฐ, ์ง๊ธ์ ์ฝ๊ฐ ์ต๊ด์ฒ๋ผ ๋ญ๋ผ๋ ๊ธฐ๋กํด๋๋๋ฐ ์์๋ฅผ ๋๋ ๊ฒ ๊ฐ๋ค. ๋ธ๋ก๊ทธ๋ณด๋ค๋ ๋ ธ์ ์ ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ ๊ธฐ๋กํด๋์ด์ ์ธ์ง ๋ธ๋ก๊ทธ์ ๋๋ฌด ๋ง์ ์๊ฐ์ ์์ง๋ ์์ผ๋ ค ํ๊ณ ์๋ค. (๊ทธ๋๋ ์ญ์ ๋จ๋ค์ด ๋ณผ ์ ์๋, ๋ฐํ์ด ๋๋ ๊ธ์ด๋ผ ์ ๊ฒฝ์ด ์ฐ์ด๋ ๊ฑด ๋ง๋๋ฏ!) ์ฌํผ ๊ณต๋ถํ ๋ด์ฉ์ ์ ๋ฆฌํ๊ณ , ๊ธฐ๋กํด๋๋๊ฑด ์ ๋ง ์ข์ ์ต๊ด ๊ฐ๋ค. ํ์ง๋ง ์ด๊ฒ๋ ๋๋ฆ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ ์์ ์ด๋ผ ์ ๋ฆฌํ ๋ถ๋ถ์ ์ ๋ฆฌํ๊ณ , ์ฐ์ ๋์ด๊ฐ ๋ถ๋ถ์ ํค์๋๋ผ๋ ์จ๋๋๊ฒ ์ข์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค. ๊ทธ๋๋ ๋ ธ์ ์ ์ ๋ฆฌ๋ฅผ ํด๋๋ฉด ํ์ํ ๋ ์ธ์ ๋ ์ง ๋ฐ๋ก ๊ฒ์ํด์ ์ฐพ์ ์๊ฐ ์๋ค๋ ์ ์ ์ฅ์ ์ด๋ค.
์ฌํผ ๋๋ ์์ง ๋ฆฌ๋์ค๋ฅผ ํ์ ํ๋ ์ค์ด๋ค. ์ค๋ ๋ง์ ๊ฐ์๋ฅผ ๋ณด๊ณ , ๊ณผ์ ๋ฅผ ๋ค์ ํ ๋ฒ ํด๋ด์ผ๊ฒ ๋ค.
๐๏ธ 23.6.25 SUN
๋ฆฌ๋์ค๋ฅผ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ค์ ๊ณต๋ถํด๋ณด๊ณ ๊ณผ์ ๋ฅผ ๋ค์ ๊ตฌํํด๋ณด์๋ค. ๋ฆฌ๋์ค๊ฐ ์คํ๋๋ ๋ก์ง๊ณผ, ์ฝ๋๋ฅผ ์์ฑํ๋๊ฒ ์ต์์น ์์์ ์ด๋ ค์ ๋ ๊ณผ์ ๊ฐ ์ด๋ฒ์ ํจ์ฌ ์์ํ๊ฒ ๋๊ปด์ ธ์ ๊ธ๋ฐฉ ์์ฑํ ์ ์์๊ณ , ์ดํด๋ ํจ์ฌ ์๋๋ ๋ฏ ํ๋ค. ํ์ต์ฐจ์์์ ์ ๊ณต๋ ์ฝ๋ ์ค ์ด๋ฏธ ๋๋์ด์ง ํด๋๊ตฌ์กฐ์ ์์ฑ๋์ด์ ธ ์๋ ์ผ๋ถ ์ฝ๋๋ฅผ ๋ณด๋ฉฐ ๋ถํธํจ๋ ๋๊ผ๋ค. ํด๋๊ตฌ์กฐ๊ฐ ์ฌ๋ฌ๊ฐ๋ก ๋๋ ์ง๊ณ , ๋ฐ๋ณต์ ์ธ ์ฝ๋๊ฐ ์๊ธด๋ค๋ ๊ฒ์ด ๋ฌด์์ธ์ง ์ดํด๊ฐ ๋์๊ณ , ์ด๋ฌํ ๋ถ๋ถ๋ค์ ๊ฐ์ ํ์ฌ ๋ฆฌ๋์ค๋ฅผ ์ข ๋ ํธํ๊ฒ ์ฌ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ด Redux Toolkit์ ์ด์ฉํ๋ ๊ฒ์ด๋ผ๊ณ ํ๋ ๊ฒ ๊ฐ๋ค. ์ด์ ๋๋์ด Redux Toolkit๋ ๋ณด๋ฌ ๊ฐ์ผ๊ฒ ๋ค..๐