Cmarket

์•ˆ์ •ํƒœยท2021๋…„ 5์›” 16์ผ
0

Study

๋ชฉ๋ก ๋ณด๊ธฐ
25/33

๐Ÿ’ฐ Cmarket

๋ฏธ์™„์„ฑ์˜ Cmarket์„ ๊ตฌ์„ฑํ•˜๋Š” React์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ๋งˆ์ € ์ž‘์„ฑํ•ด์„œ ์™„์„ฑ๋œ market์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ๋‹ค.

<ํŽ˜์ด์ง€ ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ>

  • App.js : Cmarket์—์„œ ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ ์ด ์•ˆ์—์„œ Items์™€ carItems์˜ ์ƒํƒœ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.
  • ItemListContainer.js : App.js์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ปดํฌ๋„ŒํŠธ
  • ShoppingCart.js : App.js์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ์ฐœ ๋ชฉ๋ก ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ปดํฌ๋„ŒํŠธ

<ํŽ˜์ด์ง€ ๋‚ด๋ถ€ ์ปดํฌ๋„ŒํŠธ>

  • Nav.js : App.js์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ ํŽ˜์ด์ง€ ์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ปดํฌ๋„ŒํŠธ
  • CartItem.js : ShoppingCart.js์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํ’ˆ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ปดํฌ๋„ŒํŠธ
  • Item.js : ItemListContainer.js์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํ’ˆ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ปดํฌ๋„ŒํŠธ
  • OrderSummary.js : ShoppingCart.js์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํ’ˆ์„ ์ข…ํ•ฉ์ ์œผ๋กœ ํ‘œ์‹œํ•ด์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ
  • state.js : ์ƒํ’ˆ๋“ค์ดitems์™€ cartItems๋กœ ๋ฐฐ์—ด์˜ ํ˜•ํƒœ๋กœ ๊ฐ์ฒด ์•ˆ์— ๋‹ด๊ฒจ์žˆ๋Š” ์ผ์ข…์˜ DB
// 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
    }
  ]
}

๐Ÿ“– ํŽ˜์ด์ง€ ์ „ํ™˜ : Client Side Routing

์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ ๊นŒ์ง€ ์„œ๋ฒ„๋ฅผ ํ†ตํ•œ ๋ผ์šฐํŒ…์„ ๋ฐฐ์› ๋‹ค. ์ง€๊ธˆ ์ด ํŽ˜์ด์ง€์—์„œ๋Š” ์„œ๋ฒ„๋ฅผ ํ†ตํ•˜์ง€ ์•Š๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ผ์šฐํŒ…์„ ์‹ค์‹œํ•˜๋ ค๊ณ  ํ•œ๋‹ค. ๊ทธ ์ „์— ๋‹ค์‹œ ํ•œ๋ฒˆ ๋ผ์šฐํŒ…์ด ๋ฌด์—‡์ธ๊ฐ€? ๋ฅผ ์ง‘๊ณ  ๋„˜์–ด๊ฐ€์ž.

๋ผ์šฐํŒ… : URL ์กฐ๊ฑด์— ๋”ฐ๋ฅธ ๋ถ„๊ธฐ๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ฒƒ

์„œ๋ฒ„๋ฅผ ํ†ตํ•ด์„œ ๋ผ์šฐํŒ…์„ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์€ ์ด์ „์— ์•Œ์•„๋ณด์•˜๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด Client Side Routing๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ• ๊นŒ? ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์‚ดํŽด๋ณด์ž.

return (
    <Router>
      <Nav />
      <Switch>
        <Route exact={true} path="/">
          <ItemListContainer items={items} />
        </Route>
        <Route path="/shoppingcart">
          <ShoppingCart cartItems={cartItems} items={items} />
        </Route>
      </Switch>
    </Router>
  );

์œ„ ์ฝ”๋“œ๋Š” App.js ๋‚ด์—์„œ ์ตœ์ข…์ ์œผ๋กœ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋Š” ๋ฆฌํ„ด ๊ฐ’์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด Router, Switch, Route๋กœ ๊ตฌ๋ถ„์„ ์ง€์–ด์ค๋‹ˆ๋‹ค.

๋ผ์šฐํ„ฐ๊ฐ€ / ๋ฉด ItemListContainer ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  /shoppingcart๋ฉด Soppingcart ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๊ฒฝ๋กœ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์„œ ๋‚˜๋ˆ  ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€ ๊ทธ๊ฑด Nav.js๋ฅผ ์‚ดํŽด๋ณด๋ฉด ๋œ๋‹ค.

function Nav() {

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

์œ„ ์ฝ”๋“œ์—์„œ Link ์ปดํฌ๋„ŒํŠธ์— to์†์„ฑ์„ ํ†ตํ•ด์„œ ํด๋ฆญ์‹œ ๋ผ์šฐํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋„๋ก ์„ฑ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ณ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ถ”๊ฐ€ ๋ฐ ์ƒํ’ˆ ๊ฐฏ์ˆ˜ ์—…๋ฐ์ดํŠธ : Hook

๋จผ์ € ํ•„์š”ํ•œ ๊ฒƒ์€ App.js์— ์ƒํ’ˆ๋ฆฌ์ŠคํŠธ์˜ state์™€ ์นดํŠธ๋ฆฌ์ŠคํŠธ์˜ state๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ทธ state๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ Hook์„ ํ†ตํ•ด์„œ ์ž‘์„ฑํ•œ๋‹ค.

// App.js

// initialState๋Š” import๋ฅผ ํ†ตํ•ด์„œ state์— ์žˆ๋Š” ๊ฐ’์„ ๋ฐ›์•„์˜จ ๊ฒƒ์ด๋‹ค.
function App() {

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

  return (
    ...
}

์ด ํ›„ Item ์•ˆ์— ์žˆ๋Š” ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์žฅ๋ฐ”๊ตฌ์น˜์— ์ƒํ’ˆ์ด ์ถ”๊ฐ€๋˜๊ณ  Nav ์ปดํฌ๋„ŒํŠธ์— ์ƒํ’ˆ์˜ ๊ฐฏ์ˆ˜๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

// App.js
function App() {

  const [items, setItems] = useState(initialState.items);
  const [cartItems, setCartItems] = useState(initialState.cartItems);
  
  const addToCart = (itemId) => {
    const found = cartItems.filter((el) => el.itemId === itemId)[0]
    // ์ธ์ž๋กœ ๋ฐ›์€ itemId์˜ ์ƒํ’ˆ์ด ์ด๋ฏธ cartItems์— ์žˆ์œผ๋ฉด ๊ทธ ์ƒํ’ˆ์„ found์— ํ• ๋‹นํ•ด์ค€๋‹ค.
    if(found) { // found๊ฐ€ ์žˆ์œผ๋ฉด ์ฆ‰, ์ด๋ฏธ ์นดํŠธ๋ชฉ๋ก์— ์žˆ๋Š” ๊ฒƒ์ด๋ฉด
      setQuantity(itemId, found.quantity + 1)
      //์ƒํ’ˆ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๊ทธ ์ƒํ’ˆ์˜ quantitiy๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
    }else{ // found๊ฐ€ ์—†์œผ๋ฉด ์ฆ‰, ์นดํŠธ๋ชฉ๋ก์— ์—†๋Š” ์ƒํ’ˆ์ด๋ฉด
      setCartItems([...cartItems, {itemId, quantity: 1}])
      //์ƒํ’ˆ ๋ชฉ๋ก์— ํ•ด๋‹น ์ƒํ’ˆ์˜ ์•„์ด๋””์™€ ์ˆ˜๋Ÿ‰์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.
    }
  }
  
  const setQuantity = (itemId, quantity) => { //ํ•ด๋‹น ์•„์ดํ…œ ์•„์ด๋””์™€ ์ˆ˜๋Ÿ‰์„ ์ž…๋ ฅ ๋ฐ›๋Š”๋‹ค.
    const found = cartItems.filter((el) => el.itemId === itemId)[0] //ํ•ด๋‹น ์•„์ดํ…œ ํ• ๋‹น
    const idx = cartItems.indexOf(found) // ํ•ด๋‹น ์•„์ดํ…œ์˜ ์œ„์ฐจ ๊ฐ’ ํ• ๋‹น
    const cartItem = { //ํ•ด๋‹น ์•„์ดํ…œ์„ ์ˆ˜๋Ÿ‰์„ ๋ณ€๊ฒฝํ•ด์„œ ๋‹ค์‹œ ์ •์˜ํ•œ๋‹ค.
      itemId,
      quantity
    }
    setCartItems([...cartItems.slice(0, idx), cartItem, ...cartItems.slice(idx + 1)])
    //ํ•ด๋‹น ์•„์ดํ…œ์˜ ์œ„์น˜์— ์ˆ˜๋Ÿ‰์„ ๋ณ€๊ฒฝํ•ด์„œ ๋‹ค์‹œ ์ •์˜ํ•œ ์•„์ดํ…œ์„ ๋ผ์›Œ ๋„ฃ์–ด์„œ ์žฌ ์ •์˜ํ•œ๋‹ค.
  }


  return (
    ...
    <Nav cartItems={cartItems}/>
    ...
    <ItemListContainer items={items} handleAdd={addToCart} />
    // addToCart ํ•จ์ˆ˜๋ฅผ ItemListContainer ์ปดํฌ๋„ŒํŠธ์— props๋กœ ์ „๋‹ฌํ•ด์ค€๋‹ค.
    ...
}

// ItemListContainer.js
function ItemListContainer({ items, handleAdd }) {
  const handleClick = () => handleAdd(item.id)
  // handleClick์„ ์‹คํ–‰ํ•˜๋ฉด ํ•ด๋‹น ์•„์ดํ…œ์˜ id ๊ฐ’์„ ๊ฐ€์ง€๊ณ  handleAddํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
  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>
  );
}

// Item.js
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>
  )
}

์œ„ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ์ƒํ’ˆ์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด cartItems๋ฐฐ์—ด์— ํ•ด๋‹น ์•„์ดํ…œ์ด ๋‹ด๊ธฐ๊ณ  ์ด๋ฏธ ํ•ด๋‹น ์•„์ดํ…œ์ด ์žˆ๋‹ค๋ฉด ์ˆ˜๋Ÿ‰์„ ๋Š˜๋ฆด ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  Nav์ปดํฌ๋„ŒํŠธ์— ํ‘œ์‹œ๋˜๋Š” ์ƒํ’ˆ์˜ ๊ฐฏ์ˆ˜ ๋˜ํ•œ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

// Nav.js
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>
  );
}

์žฅ๋ฐ”๊ตฌ๋‹ˆ ์˜†์— ํ‘œ์‹œ๋˜๋Š” ์ƒํ’ˆ์˜ ๊ฐฏ์ˆ˜๋Š” cartItems ๋ฐฐ์—ด์— ๊ฐ์ฒด์˜ ํ˜•ํƒœ๋กœ ๋‹ด๊ฒจ ์žˆ๋‹ค. ๋‹ค์‹œ ๋งํ•ด์„œ cartItems์˜ ๊ธธ์ด๊ฐ€ ๊ฒฐ๊ตญ ๋‹ด๊ฒจ์žˆ๋Š” ์ƒํ’ˆ์˜ ๊ฐฏ์ˆ˜๊ฐ€ ๋œ๋‹ค๋Š” ๋ง์ด๋‹ค. ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๐Ÿงบ ์žฅ๋ฐ”๊ตฌ๋‹ˆ๋กœ๋ถ€ํ„ฐ ์ œ๊ฑฐ : Hook

์žฅ๋ฐ”๊ตฌ๋‹ˆ๋กœ ๋ถ€ํ„ฐ ์ƒํ’ˆ์„ ์ œ๊ฑฐํ•˜๋ ค๋ฉด CartItem์— ์žˆ๋Š” ์‚ญ์ œ ๋ฒ„ํŠผ ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ cartItems์˜ ๋ฐฐ์—ด์—์„œ ํ•ด๋‹น ์ƒํ’ˆ์ด ์‚ฌ๋ผ์ง€๊ฒŒ ํ•˜๋ฉด ๋œ๋‹ค. ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž

// App.js
function App() {

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

  ...

  const removeFromCart = (itemId) => {
    setCartItems(cartItems.filter((el) => el.itemId !== itemId))
    // ์ธ์ž๋กœ ๋ฐ›์€ itemId์™€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฐ’๋“ค์„ ํ•„ํ„ฐ๋งํ•ด์„œ cartItems๋ฅผ ๋‹ค์‹œ ํ• ๋‹นํ•œ๋‹ค.
  }

  return (
    ...
    <ShoppingCart cartItems={cartItems} items={items} handleDelete = {removeFromCart}/>
    ...
    )
}

// ShoppingCart.js
function ShoppingCart({ items, cartItems, handleDelete: onDelete })
profile
์ฝ”๋”ฉํ•˜๋Š” ํŽญ๊ท„

0๊ฐœ์˜ ๋Œ“๊ธ€