[SEB FE] Section3 unit 4 (1) Cmarket Hooks

동화·2022년 11월 1일
0

코드스테이츠

목록 보기
25/32





APP.js

import React, { useState } from 'react';
import Nav from './components/Nav';
import ItemListContainer from './pages/ItemListContainer';
import './App.css';
import './variables.css';
import { BrowserRouter as Router, Routes, 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);

   // cartItems={cartItems} setCartItems={setCartItems}을 props로 넘겨준다
  return (
    <Router>
      <Nav />
      <Routes>
        <Route path="/" element={<ItemListContainer items={items} cartItems={cartItems} setCartItems={setCartItems}/>} />
        <Route
          path="/shoppingcart"
          element={<ShoppingCart cartItems={cartItems} items={items} setCartItems={setCartItems}/>}
        />
      </Routes>
      <img
        id="logo_foot"
        src={`${process.env.PUBLIC_URL}/codestates-logo.png`}
        alt="logo_foot"
      />
    </Router>
  );
}

export default App;






☑ 장바구니에 추가

메인 화면에서 [장바구니 담기] 버튼을 누른 후, 장바구니 페이지로 이동하면 상품이 담겨있어야 합니다.

ItemListContainer.js

onClick={(e) => handleClick(e, item.id)

장바구니 담기 버튼이 실행될 시에 받는 인자

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

function ItemListContainer({ items, cartItems, setCartItems }) {
  const handleClick = (e, id) => { 
    let newItem = cartItems
    let num = cartItems.findIndex((e) => e.itemId === id) // x-> -1
    if (num !== -1){
      newItem[num].quantity++
      setCartItems(newItem)
    } else setCartItems([...newItem, {"itemId":id, "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;

이건 findIndex를 이용하면 된다는 걸 알았을 때.. 머리 싸매며 구현했던 코드

else {
  setCartItems([...newItem, 
                {"itemId": id,
                 "quantity": 1}
               ])
}

원래 장바구니에 담겨있지 않던 아이템을 넣었을 때
새롭게 추가하는 방법이 잘 생각이 나지 않아서 애먹었던 부분이다.

그리고 처음에 for문을 이용해서 추가했던 코드

function ItemListContainer({ items, cartItems, setCartItems}) {
  const handleClick = (e, id) => {    // 클릭을 하면 클릭한 값의 아이디를 가져옴
    let newCartItem = {};
    newCartItem.itemId = id;
    newCartItem.quantity = 1;
    for (let i = 0; i < cartItems.length; i++){   
      if (cartItems[i].itemId === id){              // 클릭한 상품과 현재 상품을 (id)비교, 있으면 +1 해서 리스트에 추가만 하고
        setCartItems([...cartItems])  
        cartItems[i].quantity++
      } else setCartItems([...cartItems, newCartItem]) // 없으면 새롭게 추가 (자동으로 1이되게..? -> 처음에 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>
  );
}






☑ 장바구니 개수 숫자 표시

내비게이션 바에 상품 개수가 즉시 표시되어야 합니다.

App.js

<Router>
  ...
	<Nav cartItems={cartItems}/>
  ...
</Router>
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;






☑ 상품 개수 변경하기

장바구니 페이지에서 장바구니에 담긴 각 아이템의 개수를 변경할 수 있어야 합니다.

cartitem.js 에서

onChange={(e) => {
          handleQuantityChange(Number(e.target.value), item.id)
        }}

발견

처음에 handleQuantityChange 함수를

  const handleQuantityChange = (quantity, itemId) => {
    let idx = cartItems.findIndex((el) => el.itemId === itemId)
    cartItems[idx].quantity = quantity
    setCartItems(cartItems)
  }

이렇게 했는데 바뀌지가 않았다..
페어분이 알려주셨는데 이게 참조값이라 얕은 복사라서 상태 값을 잠시 저장만 한 것이라서 그런 거라고.. 이 실제 값을 메모리 공간에 저장하려면 깊은 복사를 해야한다고 했다.

ShoppingCart.js

       
export default function ShoppingCart({ items, cartItems, setCartItems }) {
  
...

  const handleQuantityChange = (quantity, itemId) => {
    let newCartItems = [...cartItems]
    let idx = cartItems.findIndex((el) => el.itemId === itemId)
    newCartItems[idx].quantity = quantity
    setCartItems(newCartItems)
  }
  
  ...
}

다른 방법

App.js

  const Quantity = (itemId, quantity) => {
    const itemList = cartItems.filter((el) => el.itemId === itemId)[0] // 추가될 아이템
    
    const index = cartItems.indexOf(itemList) 

    const cartItem = {
      "itemId" : itemId,
      "quantity" : quantity
    }

    setCartItems([...cartItems.slice(0, index), 
      cartItem,
  ...cartItems.slice(index + 1, cartItems.length)])
  }
  
  • [0]을 붙여주는 이유 ?
    배열 상태로 감싸져서 키:값 쌍에 접근을 하기 위해 해준다.
    괄호를 벗기는 느낌

Shoppingcart.js

 const handleQuantityChange = (quantity, itemId) => { 
   Quantity(itemId, quantity)
 }




☑ 장바구니로부터 제거

장바구니 페이지에서 [삭제] 버튼을 누른 후, 해당 상품이 목록에서 삭제되어야 합니다.

cartitem.js 내 버튼 부분확인

<button className="cart-item-delete" onClick={() => { 
  							handleDelete(item.id) }
							}>삭제</button>

ShoppingCart.js

       
export default function ShoppingCart({ items, cartItems, setCartItems }) {
  
  const handleDelete = (itemId) => {
    setCheckedItems(checkedItems.filter((el) => el !== itemId))
    setCartItems(cartItems.filter((el)=> el.itemId !== itemId))
  }
  
...



0개의 댓글