React 23장 - Cmarket Redux (2)
포스트
취소

React 23장 - Cmarket Redux (2)

React

pages/ItemListContainer.js

  • actions/index.js 로부터 addToCart, notify 함수를 받아온다.
  • redux-hoox인 useSelector,useDispatch를 가져온다.
  • useSelector를 사용하여 기존에 작성했던 reducer인 itemReducer의 상태를 지칭한다.
    • reducers/itemReducer.js 에 작성된 state는 초기값인 initialState를 갖고 있다.
    • initialState를 구조분해할당하여 items에는 상품 목록이, cartItems에는 장바구니에 담긴 상품 목록이 할당되어있다.
  • dispatch를 선언하여 useDispatch를 사용한다.
  • handleClick함수는 Item 컴포넌트의 button이 클릭됐을 때 실행되는데, 함수가 실행되면 item을 인자로 받고, 전달받는 itemitem.id이다.
    • 우리가 클릭 이벤트를 발생시킨 상품의 id를 전달받는다.
    • 함수를 실행시켜, 만약 cartItems 장바구니 안의 상품들을 map으로 새로운 배열로 갖고, 이 배열 안에 우리가 클릭한 상품의 id와 겹치는 것이 없으면 dispatch를 통해 addToCart액션을 발생시킨다.
      • addToCart액션은 ADD_TO_CARTtype을 갖고 있으며, idquantity를 추가시킨다.
    • 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에는 장바구니에 담긴 상품 목록이 할당되어있다.
  • dispatch를 선언하여 useDispatch를 사용한다.
  • 장바구니의 선택 이벤트를 만들기 위해 ShoppingCart 컴포넌트에서 사용될 checkItems 상태값을 만든다.
    • 초기값은 장바구니에 담긴 cartItemsid를 갖고 있다.
  • handleCheckChange함수는 장바구니의 체크 박스가 선택되거나 해제댔을 때 발생하는 이벤트이다.
    • CartItem 컴포넌트로 handleCheckChange함수를 보내고, CartItem 컴포넌트에서는 checkedItems상태값에 선택이 되어있으면 true, 되어있지 않으면 false를 보낸다.
    • 이때, 이벤트를 발생시킨 idchecked여부를 인자로 넘겨준다.
    • 먄약, check가 된 상황이라면 checkedItems의 초기값에 id를 더해주고,check가 해제된 상황이라면 filter를 통해 일치하는 id의 값을 제외시켜준다.
  • handleAllCheck함수는 장바구니에 모든 상품의 check를 선택하거나 해제하는 역할을 한다.
    • ShoppingCart 컴포넌트에 있는 input태그가 이벤트를 발생시키며, 이벤트가 발생할 때 모든 cartItems의 길이와 checkedItems에 들어가있는 길이가 같다는 것은, 모든 것이 해제됐거나 선택됐다는 뜻이다.
    • 이 여부에 따라 true,false값을 보내고 만약 checkedtrue라면 checkefdItems의 상태를 모든 item.id를 갖고있게 하여 모든 상품을 체크해준다.
    • 만약 checkedfalse라면 해제된 것이기 때문에, 상태값을 빈 배열로 바꿔 모든 상품을 해제한다.
  • handleQuantityChange 함수는 CartItem 컴포넌트의 number 타입의 input태그에서 이벤트가 발생할 시 실행되는 함수이다.
    • input의 값이 바뀔 때 handleQuantityChange로 이벤트를 발생시킨 요소의 valueid를 보내준다.
    • 이를 quantityid로 전달받아 dispatch를 통해 기존에 작성한 reducer의 setQuantity를 실행시킨다.
    • setQuantity함수는 SET_QUANTITY 타입의 action을 갖고 있으며, 이 액션은 itemrReducer에서 우리가 변경한 상품의 id와 일치하는 상품을 찾아, 우리가 변경한 quantity값으로 설정되도록 배열을 재구성하는 역할을 한다.
  • handleDelete 함수는 CartItem 컴포넌트의 button을 클릭하는 이벤트가 발생할 시 실행되는 함수이다.
    • CartItem 컴포넌트는 renderItems.map을 사용하여 장바구니를 구성하고 있으며, 각각의 id값을 갖고 있다.
    • 상품4번은, 4번에 해당하는 idrender.map을 통해 전달받았고, button은 넘겨받은 각각의 idhandleDelete에게 인자로 넘겨준다.
    • disptach를 통해 기존에 작성한 reducer의 removeFromCart를 실행시키고, removeFromCart를 실행하면 REMOVE_FROM_CART 타입의 액션을 실행시킨다.
    • 이 액션은 id와 전달받은 payloadid를 비교하여 상품을 제외시키는 역할을 한다.
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>
    )
}

다른 파일에 대한 설명보기

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.