Cmarket Hooks

ock·2023년 2월 23일
0

쇼핑몰 애플리케이션의 주요 기능을 구현하세요.

  • [장바구니 담기] 버튼을 이용해 장바구니에 해당 상품이 추가되도록 구현하세요.
  • 장바구니 내 [삭제] 버튼을 이용해 장바구니의 상품이 제거되도록 구현하세요.
  • 장바구니 내에서 각 아이템 개수를 변경할 수 있도록 구현하세요.
  • 장바구니의 상품 개수의 변동이 생길 때마다, 상단 내비게이션 바에 상품 개수가 업데이트되도록 구현하세요.



Cmarket


컴포넌트 구조

데이터 흐름




App.js

function App() {
  const [items, setItems] = useState(initialState.items);
  const [cartItems, setCartItems] = useState(initialState.cartItems);

  return (
    <Router>
      <Nav count={cartItems.length} />
      {/* 우리에게 필요한 건 카운트가 몇 개인지 : 길이로 > Nav 파일에도 추가. */}
      <Routes>
        <Route path="/" element={<ItemListContainer items={items} 
        cartItems={cartItems} setCartItems={setCartItems}/>} />
        {/* ItemListContainer는 cartItems와 setCartItems를 받아와야 한다. 
        > ItemListContainer 파일에도 추가. */}
        <Route
          path="/shoppingcart"
          element={<ShoppingCart cartItems={cartItems} items={items} 
          setCartItems={setCartItems}/>} />
          {/*setCartItems를 받아와야 한다. > ShoppingCart 파일에도 추가.*/}
      </Routes>
      <img
        id="logo_foot"
        src={`${process.env.PUBLIC_URL}/codestates-logo.png`}
        alt="logo_foot"
      />
    </Router>
  );
}

export default App;

---

page

ItemListContainer.js

import React from 'react';
import Item from '../components/Item';

function ItemListContainer({ items, cartItems, setCartItems }) {
  const handleClick = (itemId) => {
    //장바구니에 내가 추가하고 싶은 아이템이 이미 있는지 없는지 체크
    if(cartItems.find(el=>el.itemId === itemId) === undefined){
      //없으면 장바구니에 추가하기.
      setCartItems([...cartItems, {
        "itemId": itemId,
        "quantity": 1
      }])
    }
  }
  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([]);
    }
  };

  const handleQuantityChange = (quantity, itemId) => {
    //아이디가 일치하는 요소부터 찾아서 => quantity 값을 바꾸기
    setCartItems(cartItems.map(el=> {
      if(el.itemId === itemId){
        return {
          "itemId": itemId,
          "quantity": quantity 
        }
      } else {
        return el;
      }
    }))
  }

  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>
  )
}

component

import React from 'react';
import { Link } from 'react-router-dom';

function Nav({count}) {

  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">{count}</span>
        </Link>
      </div>
    </div>
  );
}

export default Nav;

CartItem.js

import React from 'react'

export default function CartItem({
  item,
  checkedItems,
  handleCheckChange,
  handleQuantityChange,
  handleDelete,
  quantity
}) {
  return (
    <li className="cart-item-body">
      <input
        type="checkbox"
        className="cart-item-checkbox"
        onChange={(e) => {
          handleCheckChange(e.target.checked, item.id)
        }}
        checked={checkedItems.includes(item.id) ? true : false} >
      </input>
      <div className="cart-item-thumbnail">
        <img src={item.img} alt={item.name} />
      </div>
      <div className="cart-item-info">
        <div className="cart-item-title" data-testid={item.name}>{item.name}</div>
        <div className="cart-item-price">{item.price}</div>
      </div>
      <input
        type="number"
        min={1}
        className="cart-item-quantity"
        value={quantity}
        onChange={(e) => {
          handleQuantityChange(Number(e.target.value), item.id)
        }}>
      </input>
      <button className="cart-item-delete" onClick={() => { handleDelete(item.id) }}>삭제</button>
    </li >
  )
}

Item.js

import React from 'react'

export default function Item({ item, handleClick }) {

  return (
    <div key={item.id} className="item">
      <img className="item-img" src={item.img} alt={item.name}></img>
      <span className="item-name">{item.name}</span>
      <span className="item-price">{item.price}</span>
      <button className="item-button" onClick={(e) => handleClick(e, item.id)}>장바구니 담기</button>
    </div>
  )
}

OrderSummary.js

import React from 'react'

export default function OrderSummary({ totalQty, total }) {
  return (
    <div id="order-summary-container">
      <h4>주문 합계</h4>
      <div id="order-summary">
        총 아이템 개수 : <span className="order-summary-text">{totalQty}</span>
        <hr></hr>
        <div id="order-summary-total">
          합계 : <span className="order-summary-text">{total}</span>
        </div>
      </div>
    </div >
  )
}

state.js

export const initialState =
{
  "items": [
    {
      "id": 1,
      "name": "노른자 분리기",
      "img": "../images/egg.png",
      "price": 9900
    },
    {
      "id": 2,
      "name": "2020년 달력",
      "img": "../images/2020.jpg",
      "price": 12000
    },
    {
      "id": 3,
      "name": "개구리 안대",
      "img": "../images/frog.jpg",
      "price": 2900
    },
    {
      "id": 4,
      "name": "뜯어온 보도블럭",
      "img": "../images/block.jpg",
      "price": 4900
    },
    {
      "id": 5,
      "name": "칼라 립스틱",
      "img": "../images/lip.jpg",
      "price": 2900
    },
    {
      "id": 6,
      "name": "잉어 슈즈",
      "img": "../images/fish.jpg",
      "price": 3900
    },
    {
      "id": 7,
      "name": "웰컴 매트",
      "img": "../images/welcome.jpg",
      "price": 6900
    },
    {
      "id": 8,
      "name": "강시 모자",
      "img": "../images/hat.jpg",
      "price": 9900
    }
  ],
  "cartItems": [
    {
      "itemId": 1,
      "quantity": 1
    },
    {
      "itemId": 5,
      "quantity": 7
    },
    {
      "itemId": 2,
      "quantity": 3
    }
  ]
}







뭔가 결과 실행이 이상하다...
다음에 다시 한 번 살펴보자...

profile
어제의 ock보다 성장한 오늘의 ock_FE 개발자

0개의 댓글