React 실습 - Cmarket Hooks

김도영·2022년 5월 25일
0
post-thumbnail
post-custom-banner

목표

  • react-router-dom을 이용하여 Client Side Routing 하는 방법을 학습한다.
  • useState를 이용하여 상태를 사용하는 방법을 학습한다.
  • 쇼핑묠 애플리케이션의 주요 기능을 구현해본다.
  • App.js

    import React, { useState } from 'react';
    import Nav from './components/Nav';
    import ItemListContainer from './pages/ItemListContainer';
    import './App.css';
    import {
      BrowserRouter as Router,
      Switch,
      Route,
    } from "react-router-dom";
    import ShoppingCart from './pages/ShoppingCart';
    import { initialState } from './assets/state';
    
    function App() {
    
      const [items, setItems] = useState(initialState.items);
      const [cartItems, setCartItems] = useState(initialState.cartItems);
      
    // setItems, setCartItems 변경하는 함수들도 props로 넘겨줄 수 있다.
      return (
        <Router>
          <Nav cartItems={cartItems} />
          <Switch>
            <Route exact={true} path="/">
              // cartItems={cartItems} setCartItems={setCartItems}을 props로 넘겨준다.
              <ItemListContainer items={items} cartItems={cartItems} setCartItems={setCartItems} />
            </Route>
            <Route path="/shoppingcart">
              <ShoppingCart cartItems={cartItems} items={items} setCartItems={setCartItems} />
            </Route>
          </Switch>
        </Router>
      );
    }
    
    export default App;

    ItemListContainer.js 장바구니 추가

    import React from 'react';
    import Item from '../components/Item';
    
    function ItemListContainer({ items, cartItems, setCartItems }) {
      const handleClick = (e, id) => {
        let newCart = {};
        newCart.itemId = id;
        newCart.quantity = 1;
    
        if(cartItems.length === 0) { /// 장바구니가 비어있을 때 새 상품 추가
          setCartItems([newCart])
        }
    
        for(let i = 0; i < cartItems.length; i++) {
          // 클릭한 값이 현재 id값과 같으면 그냥 추가
          if (cartItems[i].itemId === id) {
            setCartItems([...cartItems])
            cartItems[i].quantity++
          }
          
          else { // 없으면 새로 추가
            setCartItems([...cartItems, newCart])
          }
        }
      }
    
      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} />)}
          </div>
        </div>
      );
    }
    
    export default ItemListContainer;

    ShoppingCart.js 장바구니 삭제 및 수량 변경

    import React, { useState } from 'react'
    import CartItem from '../components/CartItem'
    import OrderSummary from '../components/OrderSummary'
    
    export default function ShoppingCart({ items, cartItems, setCartItems }) {
      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([]);
        }
      };
    
      // findIndex를 사용하여 인덱스 번호를 찾고
      // newCarts[인덱스번호]의 수량 = 추가한 수량 으로 바꿈
      const handleQuantityChange = (quantity, itemId) => {
        const newCarts = [...cartItems]
        let findItem = cartItems.findIndex( (item) => item.itemId === itemId )
        newCarts[findItem].quantity = quantity
        setCartItems(newCarts)
      }
    
      // cartItems에 필터를 돌려 el.itemId와 itemId값만 비교하여 같은 값만 삭제
      const handleDelete = (itemId) => {
        setCheckedItems(checkedItems.filter((el) => el !== itemId))
        setCartItems(cartItems.filter((el) => el.itemId !== 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>
      )
    }

    Nav.js

    import React from 'react';
    import { Link } from 'react-router-dom';
    
    function Nav({cartItems}) {
    
      return (
        <div id="nav-body">
          <span id="title">
            <img id="logo" src="../logo.png" alt="logo" />
            <span id="name">CMarket</span>
          </span>
          <div id="menu">
            <Link to="/">상품리스트</Link>
            <Link to="/shoppingcart">
              장바구니<span id="nav-item-counter">{cartItems.length}</span>
            </Link>
          </div>
        </div>
      );
    }
    
    export default Nav;

    profile
    Blockchain Developer
    post-custom-banner

    0개의 댓글