Jieunny์ ๋ธ๋ก๊ทธ
S3) Unit 4. [์ค์ต] CMarket Redux ๋ณธ๋ฌธ
๐ฃ CMarket์ ์ํ๋ฅผ Redux๋ก ๊ด๋ฆฌํด๋ณด์
โ๏ธ Shopping Cart Actions
โ addToCart๋ ADD_TO_CART ์ก์
์ ์์ฑํด์ผ ํฉ๋๋ค (4 ms)
โ removeFromCart๋ REMOVE_FROM_CART ์ก์
์ ์์ฑํด์ผ ํฉ๋๋ค (13 ms)
โ setQuantity๋ SET_QUANTITY ์ก์
์ ์์ฑํด์ผ ํฉ๋๋ค (2 ms)
โ๏ธ Item Reducer
โ ADD_TO_CART ์ก์
์ ๋ฐ๋ผ cartItems ์ํ๊ฐ ๋ณํด์ผ ํฉ๋๋ค (4 ms)
โ REMOVE_FROM_CART ์ก์
์ ๋ฐ๋ผ cartItems ์ํ๊ฐ ๋ณํด์ผ ํฉ๋๋ค (2 ms)
โ SET_QUANTITY ์ก์
์ ๋ฐ๋ผ cartItems ์ํ๊ฐ ๋ณํด์ผ ํฉ๋๋ค (2 ms)
โ ๋ฆฌ๋์๋ ๋ค๋ฅธ ์ํ์ ๊ฐ์ ๋ณด์กดํด์ผ ํฉ๋๋ค (2 ms)
โ๏ธ Shopping Pages
โ ShoppingCart์ cartItems๊ฐ ๋ ๋๋์ด์ผํฉ๋๋ค. (134 ms)
โ ADD_TO_CART ์ก์
์ ๋ฐ๋ผ ShoppingCart๊ฐ ๋ ๋๋์ด์ผ ํฉ๋๋ค. (103 ms)
โ REMOVE_FROM_CART ์ก์
์ ๋ฐ๋ผ ShoppingCart๊ฐ ๋ ๋๋์ด์ผ ํฉ๋๋ค. (31 ms)
โ SET_QUANTITY ์ก์
์ ๋ฐ๋ผ OrderSummary๊ฐ ๋ ๋๋์ด์ผ ํฉ๋๋ค. (26 ms)
โ Checkbox์ ์ํ์ ๋ฐ๋ผ OrderSummary๊ฐ ๋ ๋๋์ด์ผ ํฉ๋๋ค. (176 ms)
๐ฃ ๊ตฌํ ์ฝ๋
โ๏ธ InitialState ์๋ ์ ์ฒด ์์ดํ 'items'์ ์ฅ๋ฐ๊ตฌ๋์ ๋ด๊ธด ์์ดํ 'cartItems' ์ด ๋ด๊ฒจ์๋ค.
1๏ธโฃ 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";
export const NOTIFY = "NOTIFY";
export const ENQUEUE_NOTIFICATION = "ENQUEUE_NOTIFICATION";
export const DEQUEUE_NOTIFICATION = "DEQUEUE_NOTIFICATION";
// 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: itemId
}
}
}
export const setQuantity = (itemId, quantity) => {
return {
//TODO
type: SET_QUANTITY,
payload: {
itemId: itemId,
quantity: quantity
}
}
}
export const notify = (message, dismissTime = 5000) => dispatch => {
const uuid = Math.random()
dispatch(enqueueNotification(message, dismissTime, uuid))
setTimeout(() => {
dispatch(dequeueNotification())
}, dismissTime)
}
export const enqueueNotification = (message, dismissTime, uuid) => {
return {
type: ENQUEUE_NOTIFICATION,
payload: {
message,
dismissTime,
uuid
}
}
}
export const dequeueNotification = () => {
return {
type: DEQUEUE_NOTIFICATION
}
}
โฐ ์ก์ ํจ์์๋ ์ด๋ค ์ก์ ์ ์คํํ ๊ฑด์ง์ ํด๋นํ๋ type๊ณผ, ํด๋น ์ก์ ๊ณผ ๊ฐ์ด ์ ๋ฌํ payload๋ฅผ ์์ฑํ๋ค.
โฐ payload ๋ ํจ์๊ฐ ์ด๋ค ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ๊ณ ์๋์ง ํ์ธํ๊ณ ์์ฑํ๋ฉด ์ข๋ค.
2๏ธโฃ 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:
return Object.assign({}, state, {
cartItems: [...state.cartItems, action.payload]
})
// ADD_TO_CART ์ก์
์ ์ฅ๋ฐ๊ตฌ๋์ ์์ดํ
์ ์ถ๊ฐํ๋ ๊ฒ์ด๋ค.
// state์๋ ๊ธฐ๋ณธ ์์ดํ
๋ฟ๋ง ์๋๋ผ ์ฅ๋ฐ๊ตฌ๋ ์์ดํ
๋ ํฌํจ๋์ด ์๋ค.
// ์๋ ์ฅ๋ฐ๊ตฌ๋ ์์ดํ
๊ณผ ์ ๋ฌ๋ฐ์ ์์ดํ
๋ ์ถ๊ฐํด์ cartItems๋ฅผ ๊ฐฑ์ ํ๊ณ
// assign์ ์จ์ ์๋ state์ ํฉ์น๋ค.
// ๊ทธ๋ฌ๋ฉด ์๋ state์ cartItems๊ฐ ์๋ก ๊ฐฑ์ ๋ cartItems๋ก ๋ฎ์ด์ฐ์์ง๋ค.
break;
case REMOVE_FROM_CART:
//TODO
let removedCartItems = state.cartItems.filter((cartItem) => cartItem.itemId !== action.payload.itemId);
return Object.assign({}, state, {
cartItems: removedCartItems
})
// REMOVE_FROM_CART ์ก์
์ ์ฅ๋ฐ๊ตฌ๋์์ ์์ดํ
์ ์ญ์ ํ๋ ๊ฒ์ด๋ค.
// ๋ณ์ ํ๋๋ฅผ ์ ์ธํด์ ์ญ์ ํ ์์ดํ
์ด ์ ์ธ๋ ๋ฐฐ์ด์ ๋ฃ๋๋ค.
// ์๋ state์ cartItems์ filter ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ์ ๋ฌ๋ฐ์ itemId์ ๋ค๋ฅธ itemId๋ฅผ ๊ฐ์ง ์์ดํ
๋ค๋ง ๊ฐ์ ธ์จ๋ค.
// ADD_TO_CART์ ๋ง์ฐฌ๊ฐ์ง๋ก cartItems๋ฅผ ์๋ก ์ ์ธํ ๋ณ์๋ก ๊ฐฑ์ ํ๊ณ , assign์ผ๋ก ๋ฎ์ด์์ด๋ค.
break;
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)]
})
// ์๋์ ์ฆ๊ฐ์์ผ์ผ ํ ์์ดํ
์ idx๊ฐ ์ด๋ฏธ ๊ตฌํด์ ธ์๋ค.
// cartItems์ 0๋ถํฐ idx๊น์ง ์๋ฅธ ๋ฐฐ์ด, ์๋์ด ๋ณํ payload, idx๋ค์ ๋ฐฐ์ด์ ํฉ์ณ์ cartItems๋ฅผ ๊ฐฑ์ ํด์ค๋ค.
// ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ด๊ฐ ์๋์ ๋ฐ๊พธ๊ณ ์ถ์ ์์ดํ
์ ์๋๋ง ๋ฐ๋์ด์๋ค.
break;
default:
return state;
}
}
export default itemReducer;
3๏ธโฃ ItemListContainer.js
โ๏ธ ์ก์ ์ ๋ฆฌ๋์์ ์ ๋ฌํ๊ธฐ ์ํด์๋ dispatch() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
import React from 'react';
import { addToCart, notify } from '../actions/index';
import { useSelector, useDispatch } from 'react-redux';
import Item from '../components/Item';
function ItemListContainer() {
const state = useSelector(state => state.itemReducer);
const { items, cartItems } = state;
const dispatch = useDispatch();
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('์ด๋ฏธ ์ถ๊ฐ๋ ์ํ์
๋๋ค.'))
}
}
return (
<div id="item-list-container">
<div id="item-list-body">
<div id="item-list-title">์ธ๋ชจ์๋ ์ ๋ฌผ ๋ชจ์</div>
{items.map((item, idx) => <Item item={item} key={idx} handleClick={() => {
handleClick(item)
}} />)}
</div>
</div>
);
}
export default ItemListContainer;
โฐ dispatch ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ์์ดํ ์ถ๊ฐ์ ๋ํ ์ก์ ์ ์ ๋ฌํ๋ค.
โฐ dispatch์ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌํ ์ก์ ํจ์๋ฅผ ์ค๋ค.
โฐ ๊ทธ ์ก์ ํจ์๋ ํ์ํ ์ ๋ณด๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๋๋ค.
4๏ธโฃ ShoppingCart.js
import React, { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { removeFromCart, setQuantity } from '../actions';
import CartItem from '../components/CartItem'
import OrderSummary from '../components/OrderSummary'
export default function ShoppingCart() {
const state = useSelector(state => state.itemReducer);
const { cartItems, items } = state
const dispatch = useDispatch();
const [checkedItems, setCheckedItems] = useState(cartItems.map((el) => el.itemId))
const handleCheckChange = (checked, id) => {
if (checked) {
setCheckedItems([...checkedItems, id]);
}
else {
setCheckedItems(checkedItems.filter((el) => el !== id));
}
};
const handleAllCheck = (checked) => {
if (checked) {
setCheckedItems(cartItems.map((el) => el.itemId))
}
else {
setCheckedItems([]);
}
};
const handleQuantityChange = (quantity, itemId) => {
//TODO: dispatch ํจ์๋ฅผ ํธ์ถํ์ฌ ์ก์
์ ์ ๋ฌํ์ธ์.
dispatch(setQuantity(itemId, quantity));
}
const handleDelete = (itemId) => {
setCheckedItems(checkedItems.filter((el) => el !== itemId))
//TODO: dispatch ํจ์๋ฅผ ํธ์ถํ์ฌ ์ก์
์ ์ ๋ฌํ์ธ์.
dispatch(removeFromCart(itemId));
}
const getTotal = () => {
let cartIdArr = cartItems.map((el) => el.itemId)
let total = {
price: 0,
quantity: 0,
}
for (let i = 0; i < cartIdArr.length; i++) {
if (checkedItems.indexOf(cartIdArr[i]) > -1) {
let quantity = cartItems[i].quantity
let price = items.filter((el) => el.id === cartItems[i].itemId)[0].price
total.price = total.price + quantity * price
total.quantity = total.quantity + quantity
}
}
return total
}
const renderItems = items.filter((el) => cartItems.map((el) => el.itemId).indexOf(el.id) > -1)
const total = getTotal()
return (
<div id="item-list-container">
<div id="item-list-body">
<div id="item-list-title">์ฅ๋ฐ๊ตฌ๋</div>
<span id="shopping-cart-select-all">
<input
type="checkbox"
checked={
checkedItems.length === cartItems.length ? true : false
}
onChange={(e) => handleAllCheck(e.target.checked)} >
</input>
<label >์ ์ฒด์ ํ</label>
</span>
<div id="shopping-cart-container">
{!cartItems.length ? (
<div id="item-list-text">
์ฅ๋ฐ๊ตฌ๋์ ์์ดํ
์ด ์์ต๋๋ค.
</div>
) : (
<div id="cart-item-list">
{renderItems.map((item, idx) => {
const quantity = cartItems.filter(el => el.itemId === item.id)[0].quantity
return <CartItem
key={idx}
handleCheckChange={handleCheckChange}
handleQuantityChange={handleQuantityChange}
handleDelete={handleDelete}
item={item}
checkedItems={checkedItems}
quantity={quantity}
/>
})}
</div>
)}
<OrderSummary total={total.price} totalQty={total.quantity} />
</div>
</div >
</div>
)
}
โฐ 3๋ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฅ๋ฐ๊ตฌ๋ ์์ดํ ์ญ์ ์ก์ , ์๋ ๋ณ๊ฒฝ ์ก์ ์ dispatch๋ก ์ ๋ฌํด์ค๋ค.
โ๏ธ ์์ฐํ๋ฉด์ CMarket Hooks๊ณผ ๊ฐ๋ค!
'CodeStates > Training' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
S3) Unit 7. [์ค์ต] Token & Cookie ์ฌ์ฉํด์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ (0) | 2023.03.09 |
---|---|
S3) Unit 7. [์ค์ต] Cookie๋ก ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ (0) | 2023.03.07 |
S3) Unit 4. [์ค์ต] CMarket Hooks (2) | 2023.02.24 |
S3) Unit 3. [์ค์ต] Styled Component ๋ก UI ๊ตฌํํ๊ธฐ (0) | 2023.02.21 |
S3) Unit 2. [์ค์ต] Figma ํด๋ก (์ธ์คํ๊ทธ๋จ) (0) | 2023.02.17 |