-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[송형진] Sprint5, Sprint6 #251
The head ref may contain hidden characters: "React-\uC1A1\uD615\uC9C4"
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
.all-item-section { | ||
max-width: 1200px; | ||
margin: 40px auto; | ||
padding: 20px; | ||
} | ||
|
||
.all-item-header { | ||
|
@@ -10,11 +11,29 @@ | |
margin-bottom: 20px; | ||
} | ||
|
||
.all-product-list { | ||
.all-product-list.desktop { | ||
display: grid; | ||
grid-template-columns: repeat(5, 1fr); | ||
gap: 20px; | ||
list-style: none; | ||
padding: 0; | ||
margin: 0; | ||
} | ||
|
||
.all-product-list.tablet { | ||
display: grid; | ||
grid-template-columns: repeat(3, 1fr); | ||
Comment on lines
+24
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오.... grid 도 잘 사용하셨네요...! |
||
gap: 20px; | ||
list-style: none; | ||
padding: 0; | ||
margin: 0; | ||
} | ||
|
||
.all-product-list.mobile { | ||
display: grid; | ||
grid-template-columns: repeat(2, 1fr); | ||
gap: 20px; | ||
list-style: none; | ||
padding: 0; | ||
margin: 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,18 +4,32 @@ import ProductItem from "../common/product"; | |
import SearchForm from "../SearchForm/SearchForm"; | ||
import Pagination from "../Pagination/Pagination"; | ||
import "./AllProducts.css"; | ||
import useDevice from "../../hooks/useDevice"; | ||
|
||
function AllProducts() { | ||
const [allItemList, setAllItemList] = useState([]); | ||
const [selectedOption, setSelectedOption] = useState("recent"); | ||
const [currentPage, setCurrentPage] = useState(1); | ||
const [totalPages, setTotalPages] = useState(0); | ||
const [size, setSize] = useState(282); | ||
|
||
const { mode } = useDevice(); | ||
|
||
useEffect(() => { | ||
const fetchAllItems = async () => { | ||
let pageSize = 10; | ||
if (mode === "tablet") { | ||
pageSize = 6; | ||
setSize(221); | ||
} else if (mode === "mobile") { | ||
pageSize = 4; | ||
setSize(168); | ||
} else { | ||
setSize(221); | ||
} | ||
Comment on lines
+20
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 혹시 useMemo 도 배우셨을까요? 보면 mode에 따라서 pageSize 는 항상 결정되어있어요. const pageSize = useMemo(() => {
if (mode === "tablet") {
return 6;
} else if (mode === "mobile") {
return 4
} else {
return 10;
}
}, []); 그치만 아직 안배운거라면 지금 상태로도 문제는 전혀 없어요ㅎㅎ! |
||
const data = await getData({ | ||
page: currentPage, | ||
pageSize: 10, | ||
pageSize: pageSize, | ||
orderBy: selectedOption, | ||
}); | ||
|
||
|
@@ -24,7 +38,7 @@ function AllProducts() { | |
}; | ||
|
||
fetchAllItems(); | ||
}, [currentPage, selectedOption]); | ||
}, [currentPage, selectedOption, mode]); | ||
|
||
const handlePageChange = (pageNumber) => { | ||
if (pageNumber < 1 || pageNumber > totalPages) return; | ||
|
@@ -40,15 +54,15 @@ function AllProducts() { | |
setSelectedOption={setSelectedOption} | ||
/> | ||
</div> | ||
<ul className="all-product-list"> | ||
<ul className={`all-product-list ${mode}`}> | ||
{allItemList.map((item) => ( | ||
<li key={item.id}> | ||
<ProductItem | ||
imageUrl={item.images[0]} | ||
name={item.name} | ||
price={item.price} | ||
likeCount={item.favoriteCount} | ||
size={221} | ||
size={size} | ||
/> | ||
</li> | ||
))} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,28 +2,44 @@ import { useState, useEffect } from "react"; | |
import { getData } from "../../api"; | ||
import ProductItem from "../common/product"; | ||
import "./BestProducts.css"; | ||
import useDevice from "../../hooks/useDevice"; | ||
|
||
function BestProducts() { | ||
const [itemList, setItemList] = useState([]); | ||
const [currentPage, setCurrentPage] = useState(1); | ||
|
||
const [size, setSize] = useState(282); | ||
|
||
const { mode } = useDevice(); | ||
|
||
//베스트상품 가져오기 | ||
useEffect(() => { | ||
const fetchBestItems = async () => { | ||
let pageSize = 4; | ||
if (mode === "tablet") { | ||
pageSize = 2; | ||
setSize(343); | ||
} else if (mode === "mobile") { | ||
pageSize = 1; | ||
setSize(343); | ||
} else { | ||
setSize(282); | ||
} | ||
|
||
const data = await getData({ | ||
page: currentPage, | ||
pageSize: 4, | ||
pageSize: pageSize, | ||
orderBy: "favorite", | ||
}); | ||
setItemList(data.list); | ||
}; | ||
fetchBestItems(); | ||
}, []); //베스트 상품은 pagination 없으니 일단 한번만 실행 | ||
}, [mode]); //베스트 상품은 pagination 없으니 일단 한번만 실행 | ||
|
||
return ( | ||
<section className="best-section"> | ||
<h2>베스트 상품</h2> | ||
<ul className="product-list"> | ||
<ul className={`product-list ${mode}`}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이런것도 잘 이용하시네요ㅋㅋ |
||
{" "} | ||
{itemList.map((item) => ( | ||
<li key={item.id}> | ||
|
@@ -33,7 +49,7 @@ function BestProducts() { | |
name={item.name} | ||
price={item.price} | ||
likeCount={item.favoriteCount} | ||
size={282} | ||
size={size} | ||
/> | ||
</li> | ||
))} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,9 @@ | ||
@media screen and (min-width: 1200px) { | ||
.heart-section { | ||
display: flex; | ||
gap: 6px; | ||
} | ||
.heart-section { | ||
display: flex; | ||
gap: 6px; | ||
} | ||
/* @media screen and (min-width: 768px) and (max-width: 1199px) { | ||
|
||
.product-info span { | ||
position: relative; | ||
top: 5px; | ||
} | ||
@media screen and (min-width: 375px) and (max-width: 767px) { | ||
} */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import "./product.css"; | ||
import heartImage from "../../assets/images/heart.png"; | ||
import useDevice from "../../hooks/useDevice"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기에서 useDevice 는 필요없을것같긴 해요...!ㅠ |
||
|
||
function ProductItem({ imageUrl, name, price, likeCount, size }) { | ||
return ( | ||
|
@@ -26,7 +27,7 @@ function ProductItem({ imageUrl, name, price, likeCount, size }) { | |
<p>{price.toLocaleString()}원</p> | ||
<div className="heart-section"> | ||
<img src={heartImage} alt="하트이미지" /> | ||
<span>{likeCount}</span> | ||
<span>{likeCount.toLocaleString()}</span> | ||
</div> | ||
</div> | ||
</div> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,28 @@ | ||
import userIcon from "../../assets/images/user.png"; | ||
import "./Header.css"; | ||
import { Link } from "react-router-dom"; | ||
import { Link, useLocation } from "react-router-dom"; | ||
function Header() { | ||
const location = useLocation(); | ||
return ( | ||
<header className="main-header"> | ||
<div className="nav-container"> | ||
<a href="/"> | ||
<div className="brand-logo" /> | ||
</a> | ||
<nav className="nav-links"> | ||
<Link to="./pages/items.jsx">자유게시판</Link> | ||
<Link to="./pages/items.jsx">중고마켓</Link> | ||
<Link to="./">자유게시판</Link> | ||
<Link | ||
to="./items" | ||
style={{ | ||
color: | ||
location.pathname === "/items" || | ||
location.pathname === "/pages/additem" | ||
? "#3692ff" | ||
: "none", | ||
}} | ||
> | ||
중고마켓 | ||
</Link> | ||
Comment on lines
+13
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 와... 진짜 디테일하게 잘 하셨네요!ㅎㅎ 좀 더 나아가서... 만약에 메뉴가 여러개 더 추가된다고 생각해보면 메뉴 3개가 늘어나면 15줄이 추가되구요... 그럼 이부분을 따로 컴포넌트화 시켜놓는것도 방법일것같아요...! |
||
</nav> | ||
</div> | ||
<div className="user-profile"> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { useState, useEffect } from "react"; | ||
|
||
const useDevice = () => { | ||
const [windowWidth, setWindowWidth] = useState(window.innerWidth); | ||
|
||
let mode = "desktop"; | ||
|
||
if (windowWidth < 1200 && windowWidth >= 768) mode = "tablet"; | ||
else if (windowWidth < 768) mode = "mobile"; | ||
|
||
useEffect(() => { | ||
window.addEventListener("resize", (event) => { | ||
setWindowWidth(event.target.innerWidth); | ||
}); | ||
}, []); | ||
Comment on lines
+11
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이부분 조금 더 개선을 해보면... useEffect의 첫번쨰 함수가 실행되는 시점은 조금 어렵게 말하면 mount 될떄 에요. 근데 상태가 바뀌는 등으로 인해 해당 컴포넌트가 다시 mount 되면 window에 resize 이벤트가 또 추가되게 되어요ㅠ 그래서 unmount 될때 기존에 달아주었던 이벤트를 잠깐 떼어주는게 필요해요ㅠ 그런 역할을 하는 코드가 useEffect에서 return 하는 함수에요 useEffect(() => {
const handleResize = (event) => {
setWindowWidth(event.target.innerWidth);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
}
}, []); |
||
|
||
return { | ||
mode, | ||
}; | ||
}; | ||
|
||
export default useDevice; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
보통 이렇게 되면 아에 파일을 새로 만들어서 나누긴 해요ㅎㅎ
근데 이렇게 써도 문제는 전혀 없어요~