파일 구조
App.js 에서 Header.js, className = "main", Footer.js 가 있음.
className = "main" 에는 MainPage.js, ItemListPage.js, BookmarkPage.js 각각 경로설정.
MainPage.js 에서 최대 아이템4개를 렌더링해주는 MainListItems.js ,
북마킹된 아이템 최대 4개를 렌더링해주는 MainBookmarkItems.js 가 있음.
모든 아이템들은 Items.js 를 통해 렌더링.
App.js
더보기
import { useState } from "react";
import { Routes, Route } from "react-router-dom";
import Header from "./pages/Header";
import Footer from "./pages/Footer";
import MainPage from "./pages/MainPage";
import ItemListPage from "./pages/ItemListPage";
import BookmarkPage from "./pages/BookmarkPage";
import "./App.css";
function App() {
const bookmarkRender = JSON.parse(localStorage.getItem("bookmark")); // 북마크 초기값
const [bookmarkState, setBookmarkState] = useState(bookmarkRender); // 북마크 상태
return (
<div className="App">
<Header />
<main className="main">
<Routes>
<Route
path="/"
element={
<MainPage
bookmarkState={bookmarkState}
setBookmarkState={setBookmarkState}
/>
}
/>
<Route
path="/products"
element={
<ItemListPage
bookmarkState={bookmarkState}
setBookmarkState={setBookmarkState}
/>
}
/>
<Route path="/bookmark" element={<BookmarkPage />} />
</Routes>
</main>
<Footer className="footer" />
</div>
);
}
export default App;
MainPage.js
더보기
import React, { useState, useEffect } from "react";
import MainListItems from "../components/items/MainListItems";
import MainBookmarkItems from "../components/items/MainBookmarkItems";
import axios from "axios";
import classes from "./MainPage.module.css";
const MainPage = ({ bookmarkState, setBookmarkState }) => {
const [itemList, setItemList] = useState([]); // 아이템리스트 상태
const url = "http://cozshopping.codestates-seb.link/api/v1/products?count=4";
useEffect(() => {
axios.get(url).then(res => {
setItemList(res.data); // 받아온 데이터를 itemList 상태에 저장
});
}, []);
return (
<main>
<h3 className={classes.mainText}>상품 리스트</h3>
<MainListItems
itemList={itemList}
bookmarkState={bookmarkState}
setBookmarkState={setBookmarkState}
/>
<h3 className={classes.mainText}>북마크 리스트</h3>
<MainBookmarkItems
bookmarkState={bookmarkState}
setBookmarkState={setBookmarkState}
/>
</main>
);
};
export default MainPage;
MainListItems.js
더보기
import React from "react";
import Item from "./Item";
import classes from "./MainListItems.module.css";
const MainListItems = ({ itemList, bookmarkState, setBookmarkState }) => {
const handleIsBookmarked = item => {
if (bookmarkState) {
return bookmarkState.some(x => x.id === item.id);
} else {
return false;
}
};
return (
<ul className={classes.itemList}>
{itemList.map(item => {
return (
<Item
key={item.id}
item={item}
isBookmarked={handleIsBookmarked(item)}
bookmarkState={bookmarkState}
setBookmarkState={setBookmarkState}
/>
);
})}
</ul>
);
};
export default MainListItems;
MainBookmarktems.js
더보기
import Item from "./Item";
import Error from "./Error";
import classes from "./MainListItems.module.css";
const MainBookmarkItems = ({ bookmarkState, setBookmarkState }) => {
const handleIsBookmarked = item => {
// 북마크 상태 체크 함수
if (bookmarkState) {
return bookmarkState.some(x => x.id === item.id);
} else {
return false;
}
};
return (
<ul className={classes.itemList}>
{bookmarkState && bookmarkState.length !== 0 ? ( // 에러 방지
bookmarkState.slice(0, 4).map(item => {
return (
<Item
key={item.id}
item={item}
isBookmarked={handleIsBookmarked(item)}
bookmarkState={bookmarkState}
setBookmarkState={setBookmarkState}
/>
);
})
) : (
<Error /> // bookmarkState에 데이터가 없다면 Error 컴포넌트 렌더링
)}
</ul>
);
};
export default MainBookmarkItems;
Item.js
더보기
import React from "react";
import classes from "./MainListItems.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faStar } from "@fortawesome/free-solid-svg-icons";
const Item = ({ item, setBookmarkState, isBookmarked }) => {
const handleBookmark = item => {
// bookmark에 로컬스토리지 "bookmark"를 가져오고 없으면 빈배열 생성
const bookmark = JSON.parse(localStorage.getItem("bookmark")) || [];
// bookmark에 item이 있나 확인 후, 있으면 해당 index를 없으면 -1을
// existingItemIndex에 할당
const existingItemIndex = bookmark.findIndex(x => x.id === item.id);
const isExistingItem = existingItemIndex !== -1;
if (isExistingItem) {
// bookmark에 있으면 삭제, 없으면 배열 맨앞에 추가
bookmark.splice(existingItemIndex, 1);
} else {
bookmark.unshift(item);
}
// 로컬스토리지에 bookmark 덮어쓰기, State도 변경
localStorage.setItem("bookmark", JSON.stringify(bookmark));
setBookmarkState(JSON.parse(localStorage.getItem("bookmark")));
};
return (
<div className={classes.item}>
<div className={classes.imgBox}>
<img
className={classes.img}
src={item.image_url ? item.image_url : item.brand_image_url}
alt="img"
/>
<FontAwesomeIcon
className={isBookmarked ? classes.bookcolor : classes.bookmark}
size="lg"
icon={faStar}
onClick={() => {
handleBookmark(item);
}}
/>
</div>
<div className={classes.firstLine}>
{
<span className={classes.title}>
{item.title ? item.title : item.brand_name}
</span>
}
{(() => {
switch (item.type) {
case "Brand":
return <span className={classes.customer}>관심고객수</span>;
case "Product":
return (
<span className={classes.percent}>
{item.discountPercentage}%
</span>
);
default:
return "";
}
})()}
</div>
<div className={classes.firstLine}>
<span>{item.sub_title ? item.sub_title : ""}</span>
<span className={classes.follower}>
{(() => {
switch (item.type) {
case "Product":
return `${item.price
.toString()
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")}원`;
case "Brand":
return item.follower
.toString()
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
default:
return "";
}
})()}
</span>
</div>
</div>
);
};
export default Item;
'SEB_FE_44 > 과제' 카테고리의 다른 글
[coz-shopping] 무한 스크롤 (0) | 2023.05.16 |
---|---|
[coz-shopping] Modal (0) | 2023.05.15 |
Section 3 회고 (4) | 2023.05.09 |
섹션3 기술면접 정리 (0) | 2023.05.09 |
Section 2 회고 (1) | 2023.04.10 |