๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Frontend Dev/๐Ÿฅ ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  FE ๋ถ€ํŠธ์บ ํ”„

Section3 Unit4 [React] ์ƒํƒœ ๊ด€๋ฆฌ - ๊ณผ์ œ Cmarket Redux

๋ฐ˜์‘ํ˜•


Section3 Unit4 [React] ์ƒํƒœ ๊ด€๋ฆฌ - ๊ณผ์ œ Cmarket Redux

 

โญ๏ธ ๊ณผ์ œ. Cmarket Redux

โœ”๏ธ Bare Minimum Requirement

โœ… Action, Reducer๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๊ณ  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค.

 

โœ๏ธ ๊ณผ์ œ ๊ตฌํ˜„

๐Ÿ“Œ ๋ฆฌ๋•์Šค์˜ ๋ฐ์ดํ„ฐ ํ๋ฆ„ Action → Dispatch → Reducer → Store

1. ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋ณ€๊ฒฝ๋  ์ƒํƒœ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด Action ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ

2. Action ๊ฐ์ฒด๋Š” Dispatch ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌ

3. Dispatch ํ•จ์ˆ˜๋Š” Action ๊ฐ์ฒด๋ฅผ Reducer ํ•จ์ˆ˜๋กœ ์ „๋‹ฌ

4. Reducer ํ•จ์ˆ˜๋Š” Action ๊ฐ์ฒด์˜ ๊ฐ’์„ ํ™•์ธํ•˜๊ณ , ๊ทธ ๊ฐ’์— ๋”ฐ๋ผ ์ „์—ญ ์ƒํƒœ ์ €์žฅ์†Œ Store์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ

5. ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด React๋Š” ํ™”๋ฉด์„ ๋‹ค์‹œ ๋ Œ๋”๋ง

 

โœจ handleClick, handleQuantityChange, handleDelete

์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ or ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ or ์‚ญ์ œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ

// ItemListContainer.js

// ๐Ÿ“Œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ
const handleClick = (item) => {
  if (!cartItems.map((el) => el.itemId).includes(item.id)) {
    //TODO: dispatch ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์•„์ดํ…œ ์ถ”๊ฐ€์— ๋Œ€ํ•œ ์•ก์…˜์„ ์ „๋‹ฌํ•˜์„ธ์š”.
    dispatch(addToCart(item.id))
    dispatch(notify(`์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ${item.name}์ด(๊ฐ€) ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`))
  }
  else {
    dispatch(notify('์ด๋ฏธ ์ถ”๊ฐ€๋œ ์ƒํ’ˆ์ž…๋‹ˆ๋‹ค.'))
  }
}
// ShoppingCart.js

// ๐Ÿ“Œ ์ˆ˜๋Ÿ‰์„ ๋ณ€๊ฒฝํ•  ๋•Œ
const handleQuantityChange = (quantity, itemId) => {
  //TODO: dispatch ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์•ก์…˜์„ ์ „๋‹ฌํ•˜์„ธ์š”.
  dispatch(setQuantity(itemId, quantity))
}

// ๐Ÿ“Œ ์‚ญ์ œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ
const handleDelete = (itemId) => {
  setCheckedItems(checkedItems.filter((el) => el !== itemId))
  //TODO: dispatch ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์•ก์…˜์„ ์ „๋‹ฌํ•˜์„ธ์š”.
  dispatch(removeFromCart(itemId))
}
// actions > index.js

// action types
export const ADD_TO_CART = "ADD_TO_CART";
export const REMOVE_FROM_CART = "REMOVE_FROM_CART";
export const SET_QUANTITY = "SET_QUANTITY";

// actions creator functions
export const addToCart = (itemId) => {
  return {
    type: ADD_TO_CART,
    payload: {
      quantity: 1,
      itemId
    }
  }
}

export const removeFromCart = (itemId) => {
  return {
    //TODO
    type: REMOVE_FROM_CART,
    payload: {
      itemId
    }
  }
}

export const setQuantity = (itemId, quantity) => {
  return {
    //TODO
    type: SET_QUANTITY,
    payload: {
      itemId,
      quantity
    }

  }
}
// reducers > itemReducer.js

import { REMOVE_FROM_CART, ADD_TO_CART, SET_QUANTITY } from "../actions/index";
import { initialState } from "./initialState";

const itemReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TO_CART:
      //TODO
      return Object.assign({}, state, { cartItems: [...state.cartItems, action.payload] })
      
      // Spread Syntax
      // return { ...state, cartItems: [...state.cartItems, action.payload] }

    case REMOVE_FROM_CART:
      //TODO
      const updatedItems = state.cartItems.filter((item) => item.itemId !== action.payload.itemId);

      console.log(action.payload.itemId) // ์‚ญ์ œํ•  ์ œํ’ˆ์˜ itemId
      console.log("updatedItems", updatedItems) // ์ œํ’ˆ์ด ์‚ญ์ œ๋œ ํ›„์˜ ๋ฆฌ์ŠคํŠธ

      return Object.assign({}, state, { cartItems: updatedItems })

    case SET_QUANTITY:
      let idx = state.cartItems.findIndex(el => el.itemId === action.payload.itemId);
      
      //TODO
      return Object.assign({}, state, {
        cartItems: [...state.cartItems.slice(0, idx), action.payload, ...state.cartItems.slice(idx + 1)]
      })

      // Spread Syntax
      /*
      return { 
        ...state,
        cartItems: [...state.cartItems.slice(0, idx), action.payload, ...state.cartItems.slice(idx + 1)]
      }
      */
      
      // map
      /*
      return {
        ...state,
        cartItems: state.cartItems.map((el, index) => index === idx ? action.payload : el)
      }
      */

      // map (idx ์‚ฌ์šฉ X)
      /*
      return {
        ...state,
        cartItems: state.cartItems.map((el) => el.itemId === action.payload.itemId ? action.payload : el)
      }
      */
     
     
    default:
      return state;
  }
}

export default itemReducer;

 

 Reducer์˜ Immutability(๋ถˆ๋ณ€์„ฑ)

 Redux์˜ state ์—…๋ฐ์ดํŠธ๋Š” immutableํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Reducer ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑ์‹œ ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค.

 immutableํ•œ ๋ฐฉ์‹์œผ๋กœ state๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Object.assign() ๋˜๋Š” spread syntax๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 


๐ŸŒ™  ์˜ค๋Š˜์˜ ํšŒ๊ณ 

 ์ด๋ ‡๊ฒŒ ํ•œ ์ฃผ๊ฐ€ ๋ฒŒ์จ ๋์ด ๋‚ฌ๋‹ค. ์ด๋ฒˆ ์ฃผ๋Š” ๋ฆฌ์•กํŠธ๋กœ custom component ๋งŒ๋“ค๊ธฐ๋ถ€ํ„ฐ ๋ฆฌ๋•์Šค๊นŒ์ง€, ๋ฐฐ์›Œ์•ผ ํ•  ๊ฒƒ๋“ค๋„ ๋งŽ์•˜๊ณ , ๋ฐฐ์šธ ๊ฒƒ์ด ๋งŽ์œผ๋‹ˆ ์ •๋ฆฌํ•ด์•ผ ํ•  ๋ถ€๋ถ„๋„ ๋งŽ์•˜๋‹ค. ๊พธ์ค€ํžˆ ์Šต๊ด€์ฒ˜๋Ÿผ ํ•˜๋˜ ๋ธ”๋กœ๊น…๋„ ์ œ๋Œ€๋กœ ๋ชปํ•˜๊ณ , ์•„์ง ๋…ธ์…˜ ์ •๋ฆฌ๋„ ์ œ๋Œ€๋กœ ๋ชปํ•ด์„œ ์ฃผ๋ง๋™์•ˆ ์—ด์‹ฌํžˆ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณผ ์ƒ๊ฐ์ด๋‹ค. ๋ถ€ํŠธ์บ ํ”„ TIL ๋ธ”๋กœ๊น…์€ ์‚ฌ์‹ค ๋‚˜์ค‘์— ๋ฉด์ ‘ ์ž๋ฆฌ์—์„œ ์„ฑ์‹ค์„ฑ์„ ์กฐ๊ธˆ์ด๋‚˜๋งˆ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์‹œ์ž‘ํ•œ ์ด์œ ๋„ ์žˆ์—ˆ๋Š”๋ฐ, ์ง€๊ธˆ์€ ์•ฝ๊ฐ„ ์Šต๊ด€์ฒ˜๋Ÿผ ๋ญ๋ผ๋„ ๊ธฐ๋กํ•ด๋‘๋Š”๋ฐ ์˜์˜๋ฅผ ๋‘๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๋ธ”๋กœ๊ทธ๋ณด๋‹ค๋Š” ๋…ธ์…˜์— ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๊ธฐ๋กํ•ด๋‘์–ด์„œ ์ธ์ง€ ๋ธ”๋กœ๊ทธ์— ๋„ˆ๋ฌด ๋งŽ์€ ์‹œ๊ฐ„์„ ์Ÿ์ง€๋Š” ์•Š์œผ๋ ค ํ•˜๊ณ  ์žˆ๋‹ค. (๊ทธ๋ž˜๋„ ์—ญ์‹œ ๋‚จ๋“ค์ด ๋ณผ ์ˆ˜ ์žˆ๋Š”, ๋ฐœํ–‰์ด ๋˜๋Š” ๊ธ€์ด๋ผ ์‹ ๊ฒฝ์ด ์“ฐ์ด๋Š” ๊ฑด ๋งž๋Š”๋“ฏ!) ์—ฌํŠผ ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๊ณ , ๊ธฐ๋กํ•ด๋‘๋Š”๊ฑด ์ •๋ง ์ข‹์€ ์Šต๊ด€ ๊ฐ™๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ๋„ ๋‚˜๋ฆ„ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์ด๋ผ ์ •๋ฆฌํ•  ๋ถ€๋ถ„์€ ์ •๋ฆฌํ•˜๊ณ , ์šฐ์„  ๋„˜์–ด๊ฐˆ ๋ถ€๋ถ„์€ ํ‚ค์›Œ๋“œ๋ผ๋„ ์จ๋†“๋Š”๊ฒŒ ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ๊ทธ๋ž˜๋„ ๋…ธ์…˜์— ์ •๋ฆฌ๋ฅผ ํ•ด๋‘๋ฉด ํ•„์š”ํ•  ๋•Œ ์–ธ์ œ๋“ ์ง€ ๋ฐ”๋กœ ๊ฒ€์ƒ‰ํ•ด์„œ ์ฐพ์„ ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์€ ์žฅ์ ์ด๋‹ค.

 ์—ฌํŠผ ๋‚˜๋Š” ์•„์ง ๋ฆฌ๋•์Šค๋ฅผ ํŒŒ์•…ํ•˜๋Š” ์ค‘์ด๋‹ค. ์˜ค๋Š˜ ๋งˆ์ € ๊ฐ•์˜๋ฅผ ๋ณด๊ณ , ๊ณผ์ œ๋ฅผ ๋‹ค์‹œ ํ•œ ๋ฒˆ ํ•ด๋ด์•ผ๊ฒ ๋‹ค.

 

 ๐Ÿ—“๏ธ 23.6.25 SUN

 ๋ฆฌ๋•์Šค๋ฅผ ์ฐจ๊ทผ์ฐจ๊ทผ ๋‹ค์‹œ ๊ณต๋ถ€ํ•ด๋ณด๊ณ  ๊ณผ์ œ๋ฅผ ๋‹ค์‹œ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค. ๋ฆฌ๋•์Šค๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋กœ์ง๊ณผ, ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๊ฒŒ ์ต์ˆ™์น˜ ์•Š์•„์„œ ์–ด๋ ค์› ๋˜ ๊ณผ์ œ๊ฐ€ ์ด๋ฒˆ์—” ํ›จ์”ฌ ์ˆ˜์›”ํ•˜๊ฒŒ ๋Š๊ปด์ ธ์„œ ๊ธˆ๋ฐฉ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ดํ•ด๋„ ํ›จ์”ฌ ์ž˜๋˜๋Š” ๋“ฏ ํ–ˆ๋‹ค. ํ•™์Šต์ฐจ์›์—์„œ ์ œ๊ณต๋œ ์ฝ”๋“œ ์ค‘ ์ด๋ฏธ ๋‚˜๋ˆ„์–ด์ง„ ํด๋”๊ตฌ์กฐ์™€ ์ž‘์„ฑ๋˜์–ด์ ธ ์žˆ๋Š” ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉฐ ๋ถˆํŽธํ•จ๋„ ๋Š๊ผˆ๋‹ค. ํด๋”๊ตฌ์กฐ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ๋กœ ๋‚˜๋ˆ ์ง€๊ณ , ๋ฐ˜๋ณต์ ์ธ ์ฝ”๋“œ๊ฐ€ ์ƒ๊ธด๋‹ค๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ์ดํ•ด๊ฐ€ ๋˜์—ˆ๊ณ , ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„๋“ค์„ ๊ฐœ์„ ํ•˜์—ฌ ๋ฆฌ๋•์Šค๋ฅผ ์ข€ ๋” ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด Redux Toolkit์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ํ–ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. ์ด์ œ ๋“œ๋””์–ด Redux Toolkit๋„ ๋ณด๋Ÿฌ ๊ฐ€์•ผ๊ฒ ๋‹ค..๐Ÿ˜Š

๋ฐ˜์‘ํ˜•