[ SEB_FE ] Cmarket redux

seunghyo·2023년 4월 25일
0

SEB_FE

목록 보기
23/38
post-thumbnail

🐰 코드 정리 및 주석 🐰

import { combineReducers } from 'redux';
import itemReducer from './itemReducer';
import notificationReducer from './notificationReducer';

const rootReducer = combineReducers({
  itemReducer,
  notificationReducer //2개의 리듀서를 합쳐줌
});

export default rootReducer;

✅ notificationReducer

일부는 생략되었습니다

//src/reducers/notificationReducer.js

const notificationReducer = (state = {notifications:[]}, action) => {

  switch (action.type) {
    case ENQUEUE_NOTIFICATION:
      return Object.assign({}, state, {
        //notifications: ...state.notifications, action.payload 
      })
    case DEQUEUE_NOTIFICATION:
      return Object.assign({}, state, {
        //notifications:state.notifications.slice(1)
      }) 
      //state.notification에서 첫번째 요소를 뺀 나머지 배열을 notification으로...payload 초기화용?
    default:
      return state;
  }
}

export default notificationReducer;
//index.js
//생략
.
.
.
export const notify = (message, dismissTime = 5000) => dispatch => {
  const uuid = Math.random()
  dispatch(enqueueNotification(message, dismissTime, uuid))
  setTimeout(() => {
    dispatch(dequeueNotification())
  }, dismissTime)
}

export const enqueueNotification = (message, dismissTime, uuid) => { //Payload가 필요하다.
  return {
    type: ENQUEUE_NOTIFICATION,
    payload: {
      message,
      dismissTime,
      uuid
    }
  }
}

export const dequeueNotification = () => {
  return {
    type: DEQUEUE_NOTIFICATION
  }
}

import { useSelector } from 'react-redux';
import Toast from './Toast';

function NofiticationCenter() {
  const state = useSelector(state => state.notificationReducer);
  //state는 notificationReducer 선택

  return <div className="notification-container top-right">
    {
      state.notifications.map((n) =>
        <Toast key={n.uuid} text={n.message} dismissTime={n.dismissTime} /> 
          //Toast에는 time에따라 fadeout하는 함수 포함 + text 출력
      )
    }
  </div>
} //

export default NofiticationCenter

왜 굳이 dequeueNotification 함수를 작성했는지 모르겠다...이미 notification된 state를 삭제하기 위해서 인듯 한데...세션 때 다시 복습해야겠다.

✅ itemReducer

일부는 생략되었습니다

index.js (/actions)

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

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

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

새로 카트에 담는 addToCart 는 quantity를 1로 지정

//itemListContainer.js
function ItemListContainer() {
  const state = useSelector(state => state.itemReducer);
  const { items, cartItems } = state;
  const dispatch = useDispatch();
  //생성한 action을 useDispatch를 통해 발생시킬 수 있다

  const handleClick = (item) => {
    if (!cartItems.map((el) => el.itemId).includes(item.id)) {
      //카트에 있는 아이템이 아닐경우
      dispatch(addToCart(item.id)) 
      //item 담기
      dispatch(notify(`장바구니에 ${item.name}이(가) 추가되었습니다.`))
    }
    else {
      dispatch(notify('이미 추가된 상품입니다.'))
    }
  }
  .
  .
  (생략)
//itemReducer.js
import { REMOVE_FROM_CART, ADD_TO_CART, SET_QUANTITY } from "../actions/index";
import { initialState } from "./initialState";
//initialState에는 cartitems과 items 객체 정보가 들어있다.
const itemReducer = (state = initialState, action) => {

  switch (action.type) {
    case ADD_TO_CART:
      return Object.assign({}, state, {
        cartItems: [...state.cartItems, action.payload]
        //cartItems에 새 객체(action.payload) 추가.
      })


      break;
    case REMOVE_FROM_CART:
      let currentItem = state.cartItems.filter((el) => el.itemId !== action.payload.itemId)
      //필터 메소드를 활용해 payload itemId와 같지 않은 것만 currentItem으로 설정
      return Object.assign({}, state, {
        cartItems: currentItem
        // cartItems를 currentItem으로 설정
      })

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

export default itemReducer;

Object.assign() 메소드를 활용하여 기존 객체에 새 정보를 덮어씌울 수 있다. case ADD_TO_CART에서 객체를 리턴하게 되는데, 이 객체는 기존 state.cartItems에 action.payload ({quantity: 1,itemId})를 추가하여 리턴한다. case REMOVE_FROM_CART에서는 필터 메소드를 통해 payload itemId와 같지 않은 것만 currentItem으로 설정한다. 그 이후 Object.assign() 메소드를 활용하여 cartItems를 currentItem으로 설정하면 된다. (currentItem은 이미 배열이다.) case SET_QUANTITY는 action.payload와 같은 인덱스를 같는 cartItem을 찾아서 , cartItems에서 그 인덱스에 해당하는 요소를 제거한 후, quantity 값이 바뀐 action.payload(즉 새로운 값) 을 삽입해준다.



ShoppingCart.js

export default function ShoppingCart() {

  const state = useSelector(state => state.itemReducer);
  const { cartItems, items } = state
  const dispatch = useDispatch();
  const [checkedItems, setCheckedItems] = useState(cartItems.map((el) => el.itemId))

(생략)
  .
  .

  const handleQuantityChange = (quantity, itemId) => {
    dispatch(setQuantity(itemId,quantity))
  }

  const handleDelete = (itemId) => {
    setCheckedItems(checkedItems.filter((el) => el !== itemId))
    dispatch(removeFromCart(itemId));
  }

dispatch 함수를 호출하여 액션을 전달하였다.

0개의 댓글