React
pages/ItemListContainer.js
- actions/index.js 로부터
addToCart, notify
함수를 받아온다. - redux-hoox인
useSelector,useDispatch
를 가져온다. useSelector
를 사용하여 기존에 작성했던 reducer인itemReducer
의 상태를 지칭한다.- reducers/itemReducer.js 에 작성된
state
는 초기값인initialState
를 갖고 있다. initialState
를 구조분해할당하여items
에는 상품 목록이,cartItems
에는 장바구니에 담긴 상품 목록이 할당되어있다.
- reducers/itemReducer.js 에 작성된
dispatch
를 선언하여useDispatch
를 사용한다.handleClick
함수는 Item 컴포넌트의button
이 클릭됐을 때 실행되는데, 함수가 실행되면item
을 인자로 받고, 전달받는item
은item.id
이다.- 우리가 클릭 이벤트를 발생시킨 상품의
id
를 전달받는다. - 함수를 실행시켜, 만약
cartItems
장바구니 안의 상품들을map
으로 새로운 배열로 갖고, 이 배열 안에 우리가 클릭한 상품의id
와 겹치는 것이 없으면dispatch
를 통해addToCart
액션을 발생시킨다.addToCart
액션은 ADD_TO_CARTtype
을 갖고 있으며,id
와quantity
를 추가시킨다.
notify
액션 또한 실행시켜, 장바구니에 상품이 추가됐음을 알린다.- 만약 장부구니 안에 우리가 클릭한 상품과 동일한
id
를 가진 상품이 있다면, 이미 장바구니에 있는 제품이라는 말이기 때문에 새로운 경고 메시지를 출력한다.
- 우리가 클릭 이벤트를 발생시킨 상품의
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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)) {
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;
pages/ShoppingCart.js
- actions/index.js 로부터
removeToCart, setQuantity
함수를 받아온다. - redux-hoox인
useSelector,useDispatch
를 가져온다. useSelector
를 사용하여 기존에 작성했던 reducer인itemReducer
의 상태를 지칭한다.- reducers/itemReducer.js 에 작성된
state
는 초기값인initialState
를 갖고 있다. initialState
를 구조분해할당하여items
에는 상품 목록이,cartItems
에는 장바구니에 담긴 상품 목록이 할당되어있다.
- reducers/itemReducer.js 에 작성된
dispatch
를 선언하여useDispatch
를 사용한다.- 장바구니의 선택 이벤트를 만들기 위해 ShoppingCart 컴포넌트에서 사용될
checkItems
상태값을 만든다.- 초기값은 장바구니에 담긴
cartItems
의id
를 갖고 있다.
- 초기값은 장바구니에 담긴
handleCheckChange
함수는 장바구니의 체크 박스가 선택되거나 해제댔을 때 발생하는 이벤트이다.- CartItem 컴포넌트로
handleCheckChange
함수를 보내고, CartItem 컴포넌트에서는checkedItems
상태값에 선택이 되어있으면true
, 되어있지 않으면false
를 보낸다. - 이때, 이벤트를 발생시킨
id
와checked
여부를 인자로 넘겨준다. - 먄약,
check
가 된 상황이라면checkedItems
의 초기값에id
를 더해주고,check
가 해제된 상황이라면filter
를 통해 일치하는id
의 값을 제외시켜준다.
- CartItem 컴포넌트로
handleAllCheck
함수는 장바구니에 모든 상품의check
를 선택하거나 해제하는 역할을 한다.- ShoppingCart 컴포넌트에 있는
input
태그가 이벤트를 발생시키며, 이벤트가 발생할 때 모든cartItems
의 길이와checkedItems
에 들어가있는 길이가 같다는 것은, 모든 것이 해제됐거나 선택됐다는 뜻이다. - 이 여부에 따라
true
,false
값을 보내고 만약checked
가true
라면checkefdItems
의 상태를 모든item.id
를 갖고있게 하여 모든 상품을 체크해준다. - 만약
checked
가false
라면 해제된 것이기 때문에, 상태값을 빈 배열로 바꿔 모든 상품을 해제한다.
- ShoppingCart 컴포넌트에 있는
handleQuantityChange
함수는 CartItem 컴포넌트의number
타입의input
태그에서 이벤트가 발생할 시 실행되는 함수이다.input
의 값이 바뀔 때handleQuantityChange
로 이벤트를 발생시킨 요소의value
와id
를 보내준다.- 이를
quantity
와id
로 전달받아dispatch
를 통해 기존에 작성한 reducer의setQuantity
를 실행시킨다. setQuantity
함수는SET_QUANTITY
타입의action
을 갖고 있으며, 이 액션은 itemrReducer에서 우리가 변경한 상품의id
와 일치하는 상품을 찾아, 우리가 변경한quantity
값으로 설정되도록 배열을 재구성하는 역할을 한다.
handleDelete
함수는 CartItem 컴포넌트의button
을 클릭하는 이벤트가 발생할 시 실행되는 함수이다.- CartItem 컴포넌트는
renderItems.map
을 사용하여 장바구니를 구성하고 있으며, 각각의id
값을 갖고 있다. - 상품4번은, 4번에 해당하는
id
를render.map
을 통해 전달받았고,button
은 넘겨받은 각각의id
를handleDelete
에게 인자로 넘겨준다. disptach
를 통해 기존에 작성한 reducer의removeFromCart
를 실행시키고,removeFromCart
를 실행하면REMOVE_FROM_CART
타입의 액션을 실행시킨다.- 이 액션은
id
와 전달받은payload
의id
를 비교하여 상품을 제외시키는 역할을 한다.
- CartItem 컴포넌트는
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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, itemdId) => {
dispatch(setQuantity(itemId, quantity))
}
const handleDelete = (itemId) => {
setCheckedItems(checkedItems.filter((el)=> el !== itemId))
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>
<div>
<div>장바구니</div>
<span>
<input
type="checkbox"
checked={checkedItems.length === cartItems.length ? true : false}
onChange={(e)=>handleAllCheck(e.target.checked)}
></input>
<lable>전체선택</label>
</span>
<div>
{!cartItems.length? (
<div>장바구니에 아이템이 없습니다</div>
):(
<div>
{renderItems.map((item,idx)=>{
const quantity = cartItems.filter(
(el) => el.itemId === item.id
)[0].quantity;
return (
<CartItem
ket={idx}
handleCheckChange={handleCheckChange}
handleQuantityChange={handleQuantityChange}
handleDelete={handleDelete}
item={item}
checkedItems={checkedItems}
quantity={quantity}
/>
)
})}
</div>
)}
<OrderSummary total={total.price} totalQty={total.quantity} />
</div>
</div>
</div>
)
}