Post

[Day58] CartPage

[Day58] CartPage

CartPage

전체 흐름

사용자가 /cart 경로로 진입

  1. Router에서 cartPageLoader 실행
  2. cartPageLoader에서 getCartData 호출
  3. getCartData가 axios로 백엔드 API 요청
  4. 응답 데이터를 받아 cartItems로 반환
  5. 반환된 cartItems가 CartPage 컴포넌트에 전달됨

Router 설정 router.jsx

1
{ path: '/cart', element: <CartPage />, loader: cartPageLoader },
  • cartPageLoader가 실행되어 초기 데이터를 미리 로드
  • CartPage 컴포넌트가 해당 데이터를 받아 렌더링

cartPageLoader

1
2
3
4
5
6
7
8
9
10
11
export const cartPageLoader = async () => {
  try {
    const cartItems = await getCartData()
    if (!cartItems || cartItems.length === 0) {
      return { cartItems: [] }
    }
    return cartItems
  } catch (err) {
    console.log('err', err)
  }
}
  1. getCartData 함수 호출 → 장바구니 데이터를 비동기적으로 요청
  2. 응답 받은 데이터가 없거나 빈 배열이면 빈 객체 반환
  3. 그 외에는 그대로 cartItems 반환

getCartData (API 호출 함수)

1
2
3
4
5
6
7
8
export const getCartData = async () => {
  try {
    const res = await axios.get(`/api/cart/`)
    return res.data
  } catch (err) {
    console.log('err', err)
  }
}
  • /api/cart/ 경로로 GET 요청
  • 응답 데이터를 그대로 반환 (res.data)

기능

  • 장바구니 페이지에서 총 수량 및 총 금액 표시
  • 상품 수량 조절, 상품 삭제
  • 백엔드와 통신하여 장바구니 정보 수정 (GET, PUT, DELETE)

🔹 총 수량 및 금액 계산

1
2
3
4
5
6
7
// 장바구니 총 수량 계산 reduce 고차함수
const totalCount = items.reduce((sum, item) => sum + item.count, 0)
// 총 계산할 금액
const totalSum = items.reduce(
  (sum, item) => sum + Math.round(item.price * item.count * (1 - item.discount / 100)),
  0
)
  • reduce 사용해서 수량, 금액 계산
  • 할인율(discount) 고려해 계산

🔹 수량 증가: increase(id)

1
2
3
4
5
6
7
8
9
10
const increase = id => {
  // 아이템이 없으면 일찍 함수 종료
  const currentItem = items.find(item => item.id === id)
  if (!currentItem) return

  setItems(prev => prev.map(item => (item.id === id ? { ...item, count: item.count + 1 } : item)))
  const newCount = items.find(item => item.id === id).count + 1
  // cartApi에 업데이트 요청
  updateCartItemCount(id, newCount).catch(err => console.log('err', err)) // 에러처리 추가;
}
  • 로컬 state에서 먼저 수량 증가
  • 변경된 수량을 cartApi.jsupdateCartItemCount로 서버에 반영 (PUT)
1
2
3
4
5
6
7
8
9
10
export const updateCartItemCount = async (id, count) => {
  try {
    const cartItem = await axios.get(`/api/cart/${id}`)
    const updateItem = { ...cartItem.data, count }
    const res = await axios.put(`/api/cart/${id}`, updateItem)
    return res.data
  } catch (err) {
    console.log('err', err)
  }
}
  • GET으로 기존 데이터 받아온 뒤
  • count만 수정해서 PUT 요청

🔹 수량 감소: decrease(id)

1
2
3
4
5
6
7
8
9
10
11
12
const decrease = id => {
  const currentItem = items.find(item => item.id === id)
  if (!currentItem) return

  setItems(prev =>
    prev.map(item =>
      item.id === id && item.count > 1 ? { ...item, count: item.count - 1 } : item
    )
  )
  const newCount = items.find(item => item.id === id).count - 1
  if (newCount >= 1) updateCartItemCount(id, newCount).catch(err => console.log('err', err))
}
  • 수량이 1 이하가 되지 않도록 제한
  • 서버에도 동일하게 갱신 요청

🔹 아이템 삭제

1
2
3
4
5
6
const hadleDelete = id => {
  if (window.confirm('정말 삭제하시겠습니까?')) {
    setItems(prev => prev.filter(item => item.id !== id))
    removeFromCart(id)
  }
}
  • 삭제 전 confirm으로 사용자 확인
  • 삭제 후 로컬 상태와 서버 모두 갱신 (DELETE 요청)
1
2
3
4
5
6
7
8
export const removeFromCart = async id => {
  try {
    const res = await axios.delete(`/api/cart/${id}`)
    return res.data
  } catch (err) {
    console.log('err', err)
  }
}

장바구니 페이지

day53 day53


END

This post is licensed under CC BY 4.0 by the author.