본 내용의 코드는 전부 위 링크에 있으니 참고바랍니다
홈페이지 (LandingPage.js)
전 상품 정보 GET
- useEffect를 통해 최초 렌더링 시에만 작동
- useState를 통해 itemList 상태를 GET한 전 상품정보로 set
- useState를 통해 전 상품정보를 GET할 경우 loading 상태 false로 변경
...
// REST API 2-1: get all items
useEffect(() => {
async function rendering_item() {
axios
.get(`${hostURL}/api/items`)
.then((response) => {
setItemList(response.data);
setLoading(false);
})
.catch((error) => {
console.log("Error fetching items: ", error.response.data);
});
}
rendering_item();
}, []);
...
Map 함수로 상품 나열
- 삼향연산자를 통해 itemList에 원소가 있을 때만 map 함수 실행
- key를 itemId로 설정
return
...
{ itemList.length === 0 ? (
<div>
서비스 정비 중...
</div>
) : (
<div>
{itemList.map((product) => (
<div key={product.itemId}>
<Link
to={`/product/${product.itemId}`}
>
<img
src={itemImage(product)}
alt={product.name}
/>
<div>
<p>
{product.stockQuantity === 0 && (
<span>품절</span>
)}
{product.name}
</p>
<p>{product.originalPrice}원</p>
<h2>80% {product.price}원</h2>
</div>
</Link>
</div>
))}
</div> )
...
상품 이미지 구현
- 상품 이름에 따라 다른 이미지 출력
- swtich문 활용
import 삼다수 from "../../images/home/삼다수.jpg";
import 신라면 from "../../images/home/신라면.jpg";
import 컵밥 from "../../images/home/컵밥.jpg";
import 햇반 from "../../images/home/햇반.jpg";
import 구운란 from "../../images/home/구운란.jpg";
...
// item image
const itemImage = (order) => {
switch (order.name) {
case "제주 삼다수 2L (6개입)":
return 삼다수;
case "농심 신라면 (5개입)":
return 신라면;
case "오뚜기 컵밥 오삼불고기덮밥 310g":
return 컵밥;
case "햇반 백미밥 210g (3개입)":
return 햇반;
case "[EEE] 무항생제 맥반석 구운계란 (15구)":
return 구운란;
default:
return null;
}
};
...
서비스 후기 POST
- useState를 통해 feedback state 설정
- handleFeedbackChange 함수를 통해 실시간으로 feedback state이 변하도록 구현
- 후기 POST가 완료되면 feedbackLoading state가 false로 변경
...
const [feedback, setFeedback] = useState("");
const handleFeedbackChange = (event) => {
setFeedback(event.target.value);
};
const [isFeedbackLoading, setFeedbackLoading] = useState(false);
...
// REST API 3-2: POST feedback
function submitFeedback() {
if (feedback.trim() === "") {
alert("피드백을 입력해주세요!");
return;
}
setFeedbackLoading(true);
const inputs = { content: feedback };
axios
.post(`${hostURL}/api/feedbacks`, inputs)
.then(() => {
alert("피드백이 전송되었습니다. 감사합니다 :-)");
setFeedback("");
setFeedbackLoading(false);
})
.catch((error) => {
console.log(error);
});
}
...
return
...
{isFeedbackLoading ? (
<div>
<img
src={spinner}
alt="로딩 중..."
width="15%"
/>
</div>
) : (
<textarea
onChange={handleFeedbackChange}
value={feedback}
type="text"
placeholder="짧은 한 줄 소감도 큰 도움이 됩니다!"
/>
)}
<input
type="button"
value="제출하기"
onClick={submitFeedback}
/>
...
상품페이지 (DetailProductPage.js)
특정 상품 정보 GET
- useEffect를 통해 최초 렌더링 시에만 작동
- useState를 통해 product 상태를 GET한 상품정보로 set
- useState를 통해 해당 상품정보를 GET할 경우 loading 상태 false로 변경
- 존재하지 않는 productId가 API 주소에 입력될 경우 NotFoundPage(404)로 연결
...
// REST API 2-3: get item detail
useEffect(() => {
axios
.get(`${hostURL}/api/items/${productId}`)
.then((response) => {
setProduct(response.data);
setLoading(false);
})
.catch((error) => {
navigate("/404");
});
}, [productId, navigate]);
...
SNS 공유 기능
- navigator.share 함수를 통해 SNS 공유
- Android 버전 같은 경우 navigator.share 함수가 작동하지 않기에 kakao 공유로 제한
...
// templateId related to name
switch (product.name) {
case "제주 삼다수 2L (6개입)":
imageUrl = "https://i.ibb.co/Fqt03tQ/image.jpg";
break;
case "농심 신라면 (5개입)":
imageUrl = "https://i.ibb.co/hs8kHWs/image.jpg";
break;
case "오뚜기 컵밥 오삼불고기덮밥 310g":
imageUrl = "https://i.ibb.co/wsxHrfj/image.jpg";
break;
case "햇반 백미밥 210g (3개입)":
imageUrl = "https://i.ibb.co/hdqThLv/image.jpg";
break;
case "[EEE] 무항생제 맥반석 구운계란 (15구)":
imageUrl = "https://i.ibb.co/gyv3MMB/image.jpg";
break;
default:
imageUrl = "https://i.ibb.co/Rvw6N3H/landing.png";
}
// kakao share function
const kakaoButton = () => {
if (window.Kakao) {
const kakao = window.Kakao;
if (!kakao.isInitialized()) {
kakao.init("92b357c41da16ab9f3e0fa7f98cfbc30");
}
kakao.Share.sendDefault({
objectType: "feed",
content: {
title: product.name,
description: `${product.price}원`,
imageUrl: imageUrl,
link: {
mobileWebUrl: `https://www.cheapat9.com/product/${product.itemId}`,
webUrl: `https://www.cheapat9.com/product/${product.itemId}`,
},
},
buttons: [
{
title: "보러가기",
link: {
mobileWebUrl: `https://www.cheapat9.com/product/${product.itemId}`,
webUrl: `https://www.cheapat9.com/product/${product.itemId}`,
},
},
],
});
}
};
// share function
const handleShare = () => {
if (navigator.share) {
navigator.share({
title: product.name,
url: `https://www.cheapat9.com/product/${product.itemId}`,
});
} else {
kakaoButton();
}
};
...
return
...
// share button img
<img
onClick={handleShare}
className="share-icon"
src={share}
alt=""
></img>
...
구매 Modal로 props 전달
- 품절 시 구매하기 버튼 미작동
- 구매하기 버튼 클릭 시 자식 컴포넌트인 구매 Modal로 props(closeModal, product, setPosting, isClicked) 전달
return
...
// 구매하기 버튼
<div>
<Button
className={isOutOfStock ? "negative_button" : "positive-button"}
onClick={() => {
if (!isOutOfStock) {
setClicked(!isClicked);
}
}}
text={isOutOfStock ? "품절" : "바로구매"}
/>
</div>
// 구매 Modal
{isClicked && (
<div>
<Modal
closeModal={() => {
setClicked(!isClicked);
document.body.style.overflow = "auto";
}}
product={product}
setPosting={setPosting}
isClicked={isClicked}
></Modal>
</div>
)}
...
'React' 카테고리의 다른 글
React로 커머스 사이트 만들기 (5): 주문인증/주문조회 페이지 (0) | 2023.09.24 |
---|---|
React로 커머스 사이트 만들기 (4): 구매 Modal & 주문완료 페이지 (0) | 2023.09.24 |
React로 커머스 사이트 만들기 (2): REST API & json-server (0) | 2023.09.23 |
React로 커머스 사이트 만들기 (1): 세팅 (0) | 2023.09.23 |
React 개념 (230922) (0) | 2023.09.22 |