Framework/React ์™„๋ฒฝ ๊ฐ€์ด๋“œ

[React ์™„๋ฒฝ ๊ฐ€์ด๋“œ] section 11 : Practice Project: Building a Food Order App

yuri lee 2022. 10. 21. 22:42
๋ฐ˜์‘ํ˜•
์ด ๊ธ€์€ udemy์˜ React ์™„๋ฒฝ ๊ฐ€์ด๋“œ with Redux, Next.js, TypeScript ๊ฐ•์ขŒ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

 

139.  ๋ชจ๋“ˆ ์†Œ๊ฐœ

์ง€๋‚œ ์„น์…˜์—์„œ ์ค‘์š”ํ•œ ๋ฆฌ์•กํŠธ ๊ฐœ๋…๋“ค์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. useEffect, useContext, useReducer ๋“ฑ๋“ฑ / ์œ„ ๊ฐœ๋…์„ ๋ณต์Šตํ•˜๋ฉด์„œ ๋‹ค์‹œ ์‚ดํŽด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค. 

 

140.  ์„ค์ • ์‹œ์ž‘ํ•˜๊ธฐ

  • Layout folder : ex. Header 
  • UI folder: ex. Input 

 

141.  "ํ—ค๋”" ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€ํ•˜๊ธฐ

  • header ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€

 

142.  Adding the "Cart" Button Component

  • Cart Button ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€

 

143.  Adding a "Meals" Component

  • Meals ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€

 

144. Adding Individual Meal Items & Displaying Them

  • Individual Meal Items ์ถ”๊ฐ€ 

 

145. Adding a Form

const Input = (props) => {
  return (
    <div className={classes.input}>
      <label htmlFor={props.input.id}>{props.label}</label>
      <input id={props.input.id} {...props.input} />
    </div>
  );
};

export default Input;

...props.input / {type: 'text' }

const MealItemForm = (props) => {
  return (
    <form className={classes.form}>
      <Input
        label="Amount"
        input={{
          id: "amount",
          type: "number",
          min: "1",
          max: "5",
          step: "1",
          defaultValue: "1",
        }}
      />
      <button>+ Add</button>
    </form>
  );
};

export default MealItemForm;

 

146. Fixing Form Input IDs

  <Input
        label="Amount"
        input={{
          id: "amount",
          type: "number",
          min: "1",
          max: "5",
          step: "1",
          defaultValue: "1",
        }}
  />

2๊ฐ€์ง€ ๋‹จ์ ์ด ์กด์žฌํ•œ๋‹ค. 

 

1. ๋™์ผํ•œ ์ฒซ๋ฒˆ ์งธ ์ž…๋ ฅ ์š”์†Œ๊ฐ€ ์„ ํƒ๋œ๋‹ค.

2. screen reader๋Š” ๋ ˆ์ด๋ธ” + ์ž…๋ ฅ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค. (๋ชจ๋“  label์ด ๋™์ผํ•œ ์ž…๋ ฅ์„ ๊ฐ€๋ฅดํ‚ค๊ธฐ ๋•Œ๋ฌธ์—)

 

<Input
    label='Amount'
    input={{
        id: 'amount_' + props.id, // this changed!
        type: 'number',
        min: '1',
        max: '5',
        step: '1',
        defaultValue: '1',
    }}
/>
<MealItemForm id={props.id} />
<MealItem
    id={meal.id} // this is new!
    key={meal.id}
    name={meal.name}
    description={meal.description}
    price={meal.price}
/>

147. Working on the "Shopping Cart" Component

  • ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ
  • ์ถ”ํ›„ modal Wrapper๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์˜ค๋ฒ„๋ ˆ์ด๋กœ ๋ Œ๋”๋งํ•  ์˜ˆ์ •. 

 

148. Adding a Modal via a React Portal

  • public/index.html ์— ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. 
 <div id="overlays"></div>

 

149. Managing Cart & Modal State

  • cart ๋ฒ„ํŠผ ํด๋ฆญ์‹œ์—๋Š” modal ์ด ๋ณด์ด๊ณ , close ๋ฒ„ํŠผ ํ˜น์€ backdrop์„ ํด๋ฆญํ•˜๋ฉด modal์„ ๋‹ซ์„ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค.
  • ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ cart๋ฅผ ๋‹ซ๊ธฐ ์œ„ํ•ด backdrop์„ ํด๋ฆญ์— ๋ฐ”์ธ๋”ฉ ํ•˜๋ฉด ์ด backdrop์„ ๋งค์šฐ ํ•œ์ •์ ์œผ๋กœ ๋งŒ๋“ค๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์ฝ˜ํ…์ธ ์—์„œ๋Š” ์ด modal์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. backdrop ํด๋ฆญ ์‹œ ํ•ญ์ƒ cart๊ฐ€ ๋‹ซํžˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ณณ์—์„œ๋Š” props์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์„ ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋‹ฌ์˜ ์žฌ ์‚ฌ์šฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

150.  Adding a Cart Context

  • dynamic context provider
  • cart component, header component, meals component

 

151. Using the Context

  • HeaderCartButton ์ปดํฌ๋„ŒํŠธ์—์„œ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๋„๋ก ํ•˜์ž. 

 

152. Adding a Cart Reducer

Any components affected by the context are re-evaluated whnever the cart data changes. 

์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด CartProvider๋กœ ์ด๋™ํ•ด์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. CartProvider ์ปดํฌ๋„ŒํŠธ์˜ state๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค. ์ฆ‰ ์ปจํ…์ŠคํŠธ์˜ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์žฌํ‰๊ฐ€๊ฐ€ ๋œ๋‹ค. ์—ฌ๊ธฐ์—์„œ๋Š” useState ๋˜๋Š” useReducer๋ฅผ ์ž„ํฌํŠธ ํ•œ๋‹ค. ๋‘˜๋‹ค  state๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” react hooks ์ด์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” useReducer๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค. (๊ด€๋ฆฌํ•˜๋ ค๋Š” state๊ฐ€ ์กฐ๊ธˆ ๋” ๋ณต์žกํ•˜๊ธฐ ๋•Œ๋ฌธ) ์Œ์‹์ด ์ด๋ฏธ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋“ค์–ด์žˆ๋Š”์ง€์˜ ์—ฌ๋ถ€์™€ ์‚ญ์ œํ•˜๋ ค๋ฉด ๋” ๋ณต์žกํ•œ ๋กœ์ง๋„ ํ•„์š”ํ•˜๋‹ค. 
# cartReducer ์ถ”๊ฐ€
const cartReducer = (state, action) => {
  if (action.type === "ADD") {
    const updatedItems = state.items.concat(action.item);
    const updatedTotalAmount =
      state.totalAmount + action.item.price * action.item.amount;
      return {
        items: updatedItems,
        totalAmount: updatedTotalAmount
      }
  }
  return defaultCartState;
};
  • ์™ธ๋ถ€์— cartReducer ํ•จ์ˆ˜๋ฅผ ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์— ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์œ„ ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜๋Š” ๊ทธ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์ฃผ๋ณ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „ํ˜€ ํ•„์š”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋˜ํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌํ‰๊ฐ€ ๋  ๋•Œ๋งˆ๋‹ค ์žฌ์ƒ์„ฑ๋˜์–ด์„œ๋Š” ์•ˆ๋œ๋‹ค. 
const cartReducer = (state, action) => {
  if (action.type === "ADD") {
    const updatedItems = state.items.concat(action.item);
    const updatedTotalAmount =
      state.totalAmount + action.item.price * action.item.amount;
      return {
        items: updatedItems,
        totalAmount: updatedTotalAmount
      }
  }
  return defaultCartState;
};
  • state๋Š” ๋ฆฌ๋“€์„œ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” state์˜ ์ตœ์‹  state ์Šค๋ƒ…์ƒต์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜์—์„œ ์ƒˆ state๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. 

# useReducer๋ฅผ ์‚ฌ์šฉํ•œ state ์ƒ์„ฑ

  const [cartState, dispatchCartAction] = useReducer(
    cartReducer,
    defaultCartState
  );
  • useReducer๋Š” ์ •ํ™•ํžˆ ๋‘ ๊ฐœ์˜ ์š”์†Œ๋กœ ๋œ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. array destructuring์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์—์„œ ์š”์†Œ๋“ค์„ ๊บผ๋‚ด ๋ณ„๋„์˜ ์ƒ์ˆ˜์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฒซ๋ฒˆ์งธ ์š”์†Œ๋Š” ํ•ญ์ƒ state snapshot, ๋‘๋ฒˆ์งธ ์š”์†Œ๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ด๋ฅผ ํˆฅํ•ด ๋ฆฌ๋“€์„œ์— ์•ก์…˜์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. 
  • useReducer์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ˆ˜๋Š” ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ด๋ฅผ ๋ฐ”๋กœ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ดํ›„ ๋ฆฌ์•กํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ณ , ์ดˆ๊ธฐ state๋ฅผ ์„ค์ •ํ•œ๋‹ค. 

# cartContext

  const cartContext = {
    items: cartState.itmes,
    totalAmount: cartState.totalAmount,
    addItem: addItemToCartHandler,
    removeItem: removeItemFormCartHandler,
  };
 
  • cartContext ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด cartState๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๋นˆ ๋ฐฐ์—ด์„ ํ•˜๋“œ ์ฝ”๋”ฉ ํ•˜๋Š” ๋Œ€์‹  cartState.Items์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜์ž. 
 
# ์•ก์…˜์„ ์ „๋‹ฌํ•ด๋ณด์ž. 
  const addItemToCartHandler = (item) => {
    dispatchCartAction({ type: "ADD", item: item });
  };

  const removeItemFormCartHandler = (id) => {
    dispatchCartAction({ type: "REMOVE", id: id });
  };
 
  • ์ผ๋ฐ˜์ ์œผ๋กœ ์•ก์…˜์€ ๊ฐ์ฒด์ด๋‹ค. ์–ด๋–ค ์†์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ์ด๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์•ก์…˜์„ ๋ฆฌ๋“€์Šค ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์†์„ฑ ์ด๋ฆ„์œผ๋กœ type์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค. (์•ก์…˜ ์‹๋ณ„์„ ์œ„ํ•ด, ์ด๋ฆ„์€ ๋งˆ์Œ๋Œ€๋กœ ๋ถ™์—ฌ๋„ ๊ดœ์ฐฎ๋‹ค)
  • ๋ฌธ์ž์—ด์ธ ๊ฒฝ์šฐ์˜ ๊ทœ์•ฝ์— ๋”ฐ๋ผ ๋ชจ๋‘ ๋Œ€๋ฌธ์ž๋กœ ์ž‘์„ฑํ•œ๋‹ค. ๊ทœ์•ฝ์ผ ๋ฟ! ์ด์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ ๊ทœ์•ฝ๋Œ€๋กœ ํ•œ๋‹ค. ADD ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ดํ›„ ๋ฆฌ๋“€์„œ ํ•จ์ˆ˜์— ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์•ก์…˜์˜ ์ผ๋ถ€๋กœ, ํ•ญ๋ชฉ์„ ์ „๋‹ฌํ•˜๊ณ  ์‹ถ์œผ๋ฏ€๋กœ ์•ก์…˜ ๊ฐ์ฒด์— ๋‘ ๋ฒˆ์งธ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ด๋ฆ„์€ item! 
 
# CartReducer ์˜ ํ•ญ๋ชฉ ์ฒดํฌ ๋กœ์ง 
const cartReducer = (state, action) => {
  if (action.type === "ADD") {
    const updatedItems = state.items.concat(action.item);
    const updatedTotalAmount =
      state.totalAmount + action.item.price * action.item.amount;
      return {
        items: updatedItems,
        totalAmount: updatedTotalAmount
      }
  }
  return defaultCartState;
};
 
  • updatedItems ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ , state.items๋กœ ์„ค์ •ํ•œ๋‹ค. ํ˜„์žฌ state ์Šค๋ƒ…์ƒต์˜ ํ•ญ๋ชฉ์€ ๋ฆฌ๋“€์„œ์—์„œ ์ฒซ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ๋ถ€ํ„ฐ ์–ป๊ณ  ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  concate๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด๋Š” js ๋ฉ”์†Œ๋“œ๋กœ, ๋ฐฐ์—ด์— ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ push์™€ ๋‹ฌ๋ฆฌ ๊ธฐ์กด ๋ฐฐ์—ด์„ ํŽธ์ง‘ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์ƒˆ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (์ค‘์š”!)
  • state๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๋ฐฉ์‹์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ๊ฑด ์ด์ „ state ์Šค๋ƒ…์ƒต์„ ํŽธ์ง‘ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ด๋‹ค. js์˜ ์ฐธ์กฐ ๊ฐ’ ๋•Œ๋ฌธ. ์ฆ‰ ๋ฉ”๋ชจ๋ฆฌ์˜ ๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ํŽธ์ง‘๋œ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋ชจ๋ฆ„.
  • ๋”ฐ๋ผ์„œ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด state ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด concat์€ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ์ค€๋‹ค.  ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ด์ „ ๋ฐฐ์—ด์„ ํŽธ์ง‘ํ•˜๋Š” ๋Œ€์‹ ์—. (๋” ์ข‹์Œ)

153. Working with Refs & Forward Refs

addItemToCartHandler๊ฐ€ ํ˜ธ์ถœ๋˜๋„๋ก ๋งŒ๋“ค์–ด๋ณด์ž. ์ปจํ…์ŠคํŠธ ๊ฐ์ฒด์˜ addItem์„ ํ˜ธ์ถœํ•˜๋Š” ๊ณณ์œผ๋กœ ๊ฐ€์•ผํ•œ๋‹ค. (MealItmForm) Add ๋ฒ„ํŠผ์ด ํด๋ฆญ ๋˜๋ฉด, ๊ฒฐ๊ตญ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ํ•ด๋‹น ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋œ๋‹ค. 
 
# MealItemForm ์ปดํฌ๋„ŒํŠธ์— submitHandler ํ•จ์ˆ˜ ์ถ”๊ฐ€ํ•˜๊ธฐ 
  const [amountIsValid, setAmountIsValid] = useState(true);
  const amountInputRef = useRef();
  const submitHandler = (event) => {
    event.preventDefault();

    const enteredAmount = amountInputRef.current.value;
    const enteredAmountNumber = +enteredAmount;

    if (
      enteredAmount.trim().length == 0 ||
      enteredAmountNumber < 1 ||
      enteredAmountNumber > 5
    ) {
      setAmountIsValid(false);
      return;
    }
    props.onAddToCart(enteredAmountNumber);
  };
 
  • event.PreventDefault๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์ž. 
  • ์ž…๋ ฅ๋œ input ์ˆ˜๋Ÿ‰์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ref๋ฅผ ์‚ฌ์šฉํ•˜์ž. ์‚ฌ์šฉ์ž ์ง€์ • ์ปดํฌ๋„ŒํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž ์ง€์ • ์ปดํฌ๋„ŒํŠธ์—์„œ ref๊ฐ€ ์ž‘๋™ํ•˜๋„๋ก ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค. 
 # ์‚ฌ์šฉ์ž ์ง€์ • ์ปดํฌ๋„ŒํŠธ Ref ์‚ฌ์šฉ
const Input = React.forwardRef((props, ref) => {
  return (
    <div className={classes.input}>
      <label htmlFor={props.input.id}>{props.label}</label>
      <input ref={ref} {...props.input} />
    </div>
  );
});

export default Input;
  • ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ฅผ React.forwardRef ๋กœ ๊ฐ์‹ธ๋ฉด, ๊ทธ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋Š” FOrwardRef์˜ ์ธ์ˆ˜๊ฐ€ ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ref๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ref ํ”„๋กญ์„ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ์— ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 

154.  Outputting Cart Items

  const cartItems = (
    <ul className={classes["cart-itemse"]}>
      {cartCtx.items.map((item) => (
        <CartItem
          key={item.id}
          name={item.name}
          amount={item.amount}
          price={item.price}
          onRemove={cartItemRemoveHandler.bind(null, item.id)}
          onAdd={cartItemAddHandler.bind(null, item)}
        />
      ))}
    </ul>
  );

Now on both these functions you should call bind and bind no item ID. This ensures that the idea of the to be added or removed item is passed here to remove handler and on end you should also call bind and bind null and pass the overall item. You'll learn that bind pre-configure as a function for future execution and basically allows you to pre-configure the argument that function will receive when it's being executed. And that's something we need here to ensure that both these functions do receive the ID or the item respectively.

155.  Working on a More Complex Reducer Logic

  • ๋ณด์ถฉ ์˜ˆ์ •

156.  Making Items Removable

  • ๋ณด์ถฉ ์˜ˆ์ •

157.  Using the useEffect Hook

  • ๋ณด์ถฉ ์˜ˆ์ •

158. Module Resources

  • resources

https://www.udemy.com/course/best-react/

๋ฐ˜์‘ํ˜•