728x90

SingleProductPage.jsx
import { useState } from "react";
import "./SingleProductPage.css";
const product = {
id: 1,
title: "์ํ ํ์ดํ",
description:
"Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime aliquid rerum a? Fugiat soluta facilis deleniti voluptatibus ab architecto dolores a, vero, beatae veniam error doloribus quia laudantium? Error fuga consequuntur quia accusantium? Consequatur modi laboriosam saepe culpa, ab atque.",
price: 9900,
images: [
],
stock: 10,
};
const SingleProductPage = () => {
//์ฒ์ ์์ ์ด๋ฏธ์ง ๋ฒํธ๋ 0์ -> product.images[0] = image1 ์ ์๋ฏธํจ
const [selectedImage, setSelectedImage] = useState(0);
return (
<section className="align_center single_product">
<div className="align_center">
<div className="single_product_thumbnails">
{/* product ์์ images๋ฅผ map ๋ฐ๋ณตํ๋ค. */}
{product.images.map((image, index) => (
<img
src={image}
alt={product.title}
// css ๋ selectedImage state๊ฐ index์ผ ๊ฒฝ์ฐ selected_image ์ ์ฉํ๋ค.
className={selectedImage === index ? "selected_image" : ""}
// ํด๋ฆญํ๋ฉด index๋ก ์คํ
์ดํธ ์ ์ฅ
onClick={() => setSelectedImage(index)}
/>
))}
</div>
<img
// ์ด๋ฏธ์ง๋ ์ ํ๋ index์ ์ด๋ฏธ์ง๋ก ์ถ๋ ฅํ๋ค.
src={product.images[selectedImage]}
alt={product.title}
className="single_product_display"
/>
</div>
<div className="single_product_details"></div>
</section>
);
};
export default SingleProductPage;
SingleProductPage.jsx
.single_product {
justify-content: center;
padding: 32px 48px;
}
.single_product_thumbnails {
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 14px;
padding: 8px;
margin: 16px;
}
.single_product_thumbnails img {
width: 80px;
height: 80px;
object-fit: cover;
border-radius: 5px;
cursor: pointer;
transition: all 0.2s ease-in-out;
}
.single_product_display {
width: 600px;
height: 600px;
object-fit: cover;
border-radius: 10px;
}
.selected_image {
transform: scale(1.12);
}
App.jsx
<main>
{/* <HomePage /> */}
{/* <ProductsPage /> */}
<SingleProductPage />
</main>

๊ทธ๋ฆฌ๊ณ ์ฌ์ง ์์ ์ํ์ ๋ํ ์ผ์ ์ถ๊ฐํ๋ค.
(ํ ์คํธ)๋ฐ์ดํฐ๋ก ์ฌ์ฉํ product ๊ฐ์ฒด๋ฅผ ์ํ๋ก ํ๋ ๋ง๋ ๋ค.
์์๋ ์๋์ ๊ฐ์ด id, title, description(์์ธ์ ๋ณด) , price(๊ฐ๊ฒฉ), images(์ด๋ฏธ์ง ๋งํฌ), stock ์๋
import { useState } from "react";
import "./SingleProductPage.css";
const product = {
id: 1,
title: "์ํ ํ์ดํ",
description:
"Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime aliquid rerum a? Fugiat soluta facilis deleniti voluptatibus ab architecto dolores a, vero, beatae veniam error doloribus quia laudantium? Error fuga consequuntur quia accusantium? Consequatur modi laboriosam saepe culpa, ab atque.",
price: 9900,
images: [
],
stock: 10,
};
const SingleProductPage = () => {
const [selectedImage, setSelectedImage] = useState(0);
return (
<section className="align_center single_product">
<div className="align_center">
<div className="single_product_thumbnails">
{/* product ์์ images๋ฅผ map ๋ฐ๋ณตํ๋ค. */}
{product.images.map((image, index) => (
<img
src={image}
alt={product.title}
// css ๋ selectedImage state๊ฐ index์ผ ๊ฒฝ์ฐ selected_image ์ ์ฉํ๋ค.
className={selectedImage === index ? "selected_image" : ""}
// ํด๋ฆญํ๋ฉด index๋ก ์คํ
์ดํธ ์ ์ฅ
onClick={() => setSelectedImage(index)}
/>
))}
</div>
<img
// ์ด๋ฏธ์ง๋ ์ ํ๋ index์ ์ด๋ฏธ์ง๋ก ์ถ๋ ฅํ๋ค.
src={product.images[selectedImage]}
alt={product.title}
className="single_product_display"
/>
</div>
{/* ์ํ ๋ํ
์ผ */}
<div className="single_product_details">
<h1 className="single_product_title">{product.title}</h1>
<p className="single_product_description">{product.description}</p>
<p className="single_product_price">
๏ฟฆ {product.price.toLocaleString("ko-KR")} ์
</p>
<h2 className="quantity_title">๊ตฌ๋งค๊ฐ์:</h2>
<div className="align_center quantity_input">
{/* <QuantityInput /> */}
</div>
<button className="search_button add_cart">์ฅ๋ฐ๊ตฌ๋ ์ถ๊ฐ</button>
</div>
</section>
);
};
export default SingleProductPage;
SingleProductPage.css
/* ์ํ ๋ํ
์ผ */
.single_product_details {
width: 35%;
padding: 16px 24px;
}
.single_product_title {
margin-bottom: 16px;
font-size: 32px;
}
.single_product_description {
margin-bottom: 16px;
line-height: 1.4;
}
.single_product_price {
margin-bottom: 16px;
font-size: 24px;
font-weight: 600;
}
.quantity_title {
font-size: 20px;
font-weight: 700;
margin-bottom: 3px;
}
.quantity_input {
font-size: 20px;
font-weight: 700;
margin: 5px 0 16px;
}
.add_cart {
width: fit-content;
padding: 8px 18px;
}

๊ทธ๋ฆฌ๊ณ ์ํ ์๋์ ํ์ํ QuantityInput ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋ค.

QuantityInput.jsx
import "./QuantityInput.css";
const QuantityInput = () => {
return (
<>
<button className="quantity_input_button" disabled>
{" "}
-{" "}
</button>
<p className="quantity_input_count">1</p>
<button className="quantity_input_button"> + </button>
</>
);
};
export default QuantityInput;
QuantityInput.css
.quantity_input_button {
width: 35px;
height: 35px;
font-size: 25px;
background-color: #ff8848;
color: #fff;
border: none;
border-radius: 100%;
cursor: pointer;
}
.quantity_input_button:disabled {
opacity: 0.3;
cursor: default;
}
.quantity_input_count {
margin: 0 40px;
text-align: center;
}
SingleProductPage.jsx์์ ์ปดํฌ๋ํธ ์ ์ฉํ๋ค.
<h2 className="quantity_title">๊ตฌ๋งค๊ฐ์:</h2>
<div className="align_center quantity_input">
<QuantityInput />
</div>

'FRONTEND > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [myCart] ์ฃผ๋ฌธ ๋ด์ญ ํ์ด์ง (0) | 2023.12.19 |
|---|---|
| [myCart] ์ฅ๋ฐ๊ตฌ๋ ํ์ด์ง (0) | 2023.12.19 |
| [myCart] ์ํํ์ด์ง ์์ฑ (์ฌ์ด๋ ๋ฐ/ ์ํ ๋ชฉ๋ก) (2) | 2023.12.19 |
| [myCart] FeaturedProducts ์ปดํฌ๋ํธ ๋ฐ ProductCard ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ (0) | 2023.12.19 |
| [myCart] ํํ์ด์ง ์์ฑ ๋ฐ heroSection ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ (1) | 2023.12.19 |