🛒 장바구니
장바구니 수량 업데이트
- cartApi.js
export const updateCartItem = async (id, count) => {
try {
// id에 해당하는 상품 가져오기
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('[error]', err)
}
}
- CartPage.js
const decrease = id => {
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) updateCartItem(id, newCount)
}
const increase = id => {
setItems(prev => prev.map(item => (item.id === id ? { ...item, count: item.count + 1 } : item)))
const newCount = items.find(item => item.id === id).count + 1
updateCartItem(id, newCount)
}
장바구니 상품 삭제
- cartApi.js
export const removeFromCart = async id => {
try {
const res = await axios.delete(`/api/cart/${id}`)
return res.data
} catch (err) {
console.log('[error]', err)
}
}
- CartPage.js
const handleDelete = id => {
if (window.confirm('정말 삭제하시겠습니까?')) {
setItems(prev => prev.filter(item => item.id !== id))
removeFromCart(id)
}
}
🛍️ Shop 페이지
카테고리, 정렬 필터
import React, { useState } from 'react'
import css from './ShopPage.module.css'
const ShopPage = () => {
const [isDown, setIsDown] = useState(false)
return (
<main className={css.shopPage}>
<h2>Shop All</h2>
<div className={css.filterFn}>
{/* 카테고리 선택 기능 */}
<div className={css.category}>
<button className={css.active}>전체상품</button>
<button>신상품(new)</button>
<button>인기상품(top)</button>
</div>
{/* 정렬 기능 */}
<div className={`${css.sort} ${isDown ? css.active : ''}`}>
<div className={css.sortHeader} onClick={() => setIsDown(!isDown)}>
<p>등록순</p>
<i className={`bi bi-chevron-${isDown ? 'up' : 'down'}`}></i>
</div>
<ul>
<li className={css.active}>등록순</li>
<li>낮은 가격순</li>
<li>높은 가격순</li>
<li>낮은 할인순</li>
<li>높은 할인순</li>
</ul>
</div>
</div>
<div className={css.productList}>
<ul className={css.list}>
<li>상품리스트</li>
<li>상품리스트</li>
<li>상품리스트</li>
</ul>
<div className={css.paginationArea}>
<button>
<i className="bi bi-chevron-left"></i>
</button>
<button>1</button>
<button className={css.active}>2</button>
<button>3</button>
<button>
<i className="bi bi-chevron-right"></i>
</button>
</div>
</div>
</main>
)
}
export default ShopPage
.cartList {
display: flex;
flex-direction: column;
gap: var(--fs12);
margin: var(--fs33) auto;
}
.cartItem {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--fs12);
border-radius: var(--fs12);
padding: var(--fs12);
background-color: var(--dark-colors-white-dark);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
.cartItem:hover {
transform: translateY(-5px);
}
.cartImg {
border-radius: var(--fs12);
overflow: hidden;
width: 100px;
}
.cartImg img {
width: 100%;
height: 100%;
object-fit: cover;
}
.title {
flex: 1;
cursor: pointer;
}
.title:hover {
font-weight: bold;
}
.price,
.sum {
width: 110px;
text-align: right;
}
.btnArea {
background-color: #dcdbdb;
border-radius: var(--fs8);
}
.btnArea button {
border: none;
outline: none;
padding: var(--fs12) var(--fs20);
font-size: var(--fs16);
background-color: transparent;
}
.btnArea span {
display: inline-block;
width: 50px;
text-align: center;
}
.deleteBtn {
padding: var(--fs12);
cursor: pointer;
}
.deleteBtn:hover i {
color: var(--light-colors-errors-light);
}
.totalPrice {
text-align: right;
font-size: var(--fs26);
}
.empty {
text-align: center;
padding: var(--fs33);
}
@media (max-width: 900px) {
.cartItem {
display: grid;
grid-template-columns: 1fr 1fr 50px;
grid-template-rows: repeat(4, 1fr);
}
.cartImg {
grid-column: 1/2;
grid-row: 1/5;
width: 100%;
height: 100%;
}
.title,
.price,
.sum {
grid-column: 2/4;
width: 100%;
}
.btnArea {
order: 1;
display: flex;
align-items: center;
justify-content: space-between;
}
.deleteBtn {
order: 5;
}
}
@media (max-width: 500px) {
.cartItem {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
.cartItem > div {
width: 100%;
}
.cartItem > .btnArea {
width: calc(100% - 80px);
}
.cartItem > .deleteBtn {
width: 50px;
}
}
728x90
반응형
'LG 유플러스 유레카 SW > React' 카테고리의 다른 글
[#60] React - Hook + 성능 최적화 정리 (0) | 2025.04.23 |
---|---|
[#59] React 쇼핑몰 - Shop 페이지 상품 필터링/정렬 + 페이지네이션 (0) | 2025.04.22 |
[#57] React 쇼핑몰 - 상품 상세 페이지(탭, 슬라이더) + 장바구니 조회/추가 (0) | 2025.04.18 |
[#56] React 쇼핑몰 - 상품 상세 페이지 (1) | 2025.04.17 |
[#55] React 쇼핑몰 - 스켈레톤 UI + 반응형 메인 리스트 페이지 (0) | 2025.04.16 |