-
Notifications
You must be signed in to change notification settings - Fork 20
[김희진] sprint5 #47
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 #47
The head ref may contain hidden characters: "React-\uAE40\uD76C\uC9C4-sprint1"
Conversation
- search encodeURIComponent delete - get best items pageSize edit & code cleanup - if no items when searching(NoneItem)
|
스프리트 미션 하시느라 수고 많으셨어요. |
| /node_modules | ||
| /.pnp | ||
| .pnp.js | ||
| .env |
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.
굿굿 ! .env파일을 작성하고 형상관리에서 제외하셨군요 ! 👍
| const BASE_URL = process.env.REACT_APP_BASE_URL; | ||
|
|
||
| export async function getProducts(params) { | ||
| const { page, pageSize, orderBy, keyword } = params; | ||
| const response = await axios.get(`${BASE_URL}/products`, { | ||
| params: { page, pageSize, orderBy, keyword }, | ||
| }); | ||
|
|
||
| return response.data; | ||
| } |
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.
크으 ~ 정말 깔끔한 API관리 ! 😊
BASE_URL도 설정하셨네요 👍👍
| @@ -0,0 +1,12 @@ | |||
| import axios from "axios"; | |||
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.
instacne를 설정하셔서 사용하시는걸 추천드려요 !
어떻게 세팅하면 될까? 🤔
instance를 만들어서 export를 하고 사용해보는 것 정도로 시도해보면 좋을 것 같아요. axios-instance 파일을 만들어서 instance를 생성하고 export한 후 사용해보는건 어떨까요?
다음과 같이 만들어볼 수 있어요:
const baseURL = process.env.NEXT_PUBLIC_LINKBRARY_BaseURL;
const instance = axios.create({
baseURL: baseURL,
headers: {
'Content-Type': 'application/json',
},
});
export default instance| export default function AllItems({ items, sortOption, onChange, setKeyword }) { | ||
| return ( | ||
| <S.AllContainer> | ||
| <S.AllHeader> | ||
| <S.Div> | ||
| <S.Title>전체 상품</S.Title> | ||
| <Link to="/addItem"> | ||
| <S.AddBtnForMedia>상품 등록하기</S.AddBtnForMedia> | ||
| </Link> | ||
| </S.Div> | ||
| <S.Filter> | ||
| <Search onSearch={setKeyword} /> | ||
| <Link to="/addItem"> | ||
| <S.AddBtn>상품 등록하기</S.AddBtn> | ||
| </Link> | ||
| <Dropdown sortOption={sortOption} list={list} onChange={onChange} /> | ||
| </S.Filter> | ||
| </S.AllHeader> | ||
| {items.length !== 0 ? ( | ||
| <S.ItemCardContainer> | ||
| {items.map((items, idx) => ( | ||
| <ItemCard key={idx} list="all" {...items} /> | ||
| ))} | ||
| </S.ItemCardContainer> | ||
| ) : ( | ||
| <NoneItem /> | ||
| )} | ||
| </S.AllContainer> | ||
| ); | ||
| } |
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.
크으 ~ 깔끔하네요.
컴포넌트를 선언하고 props를 적절히 사용하고 있군요.
컴포넌트 내부에 상태가 없으며 prosp로만 설계 되었네요? 😉
| useEffect(() => { | ||
| updateBestItems(); | ||
| window.addEventListener("resize", updateBestItems); | ||
|
|
||
| return () => { | ||
| window.removeEventListener("resize", updateBestItems); | ||
| }; | ||
| }, [updateBestItems]); |
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.
굿굿 이벤트 리스너 생성과 제거까지 ! 😊😊
그리고 의존성까지 잘 처리하셨네요 ! 훌륭합니다 ! 👍👍👍
| import { getProducts } from "../../../api/products"; | ||
| import Paging from "../../Paging/Paging"; | ||
|
|
||
| export default function ItemPage() { |
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.
(의견/제안) 해당 페이지에 책임이 많은 것 같아요.
items, bestItems 그리고 페이지네이션에 관련된 상태들까지 페이지에서 관리하고 있어요.
그렇다면 AllItems의 상태가 변경되면 되는 상황에서도 BestItems도 리렌더링 될 것이 우려가 됩니다 !
관련 없는 서로 다른 상태들로 인해 리렌더링이 될 수도 있겠군요.
관련된 상태들을 각각의 컴포넌트로 인계하는건 어떨지 제안드리고 싶어요.
다음은 예
| return ( | ||
| <S.Container> | ||
| <BestItems bestItems={responsiveItems} updateBestItems={updateBestItems} /> | ||
| <AllItems items={items} sortOption={sortOption} onChange={handleChangeClick} setKeyword={setKeyword} /> |
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.
(이어서) 예를 들어서 다음과 같이 작성해볼 수 있어요:
GPT로 작성된 임의의 코드입니다:
import React, { useEffect, useState } from "react";
function AllItems() {
const [items, setItems] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [keyword, setKeyword] = useState("");
const [totalItems, setTotalItems] = useState(0);
const [sortOption, setSortOption] = useState("최신순");
useEffect(() => {
if (window.innerWidth <= 767) setPageSize(4);
else if (window.innerWidth >= 768 && window.innerWidth <= 1199) setPageSize(6);
else setPageSize(10);
}, []);
useEffect(() => {
const orderByValue = sortOption === "최신순" ? "recent" : "favorite";
getProducts({ page: currentPage, pageSize, orderBy: orderByValue, keyword }).then((result) => {
if (result) {
setItems(result.list);
setTotalItems(result.totalCount);
}
});
}, [currentPage, pageSize, sortOption, keyword]);
const handleSortChange = (option) => {
setSortOption(option);
};
return (
<div>
<div>
<button onClick={() => handleSortChange("최신순")}>최신순</button>
<button onClick={() => handleSortChange("좋아요순")}>좋아요순</button>
</div>
{items.map((item) => (
<div key={item.id}>{item.name}</div>
))}
<Paging currentPage={currentPage} pageSize={pageSize} totalItemsCount={totalItems} setPage={setCurrentPage} />
</div>
);
}
export default AllItems;|
|
||
| return ( | ||
| <S.Container> | ||
| <BestItems bestItems={responsiveItems} updateBestItems={updateBestItems} /> |
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.
(이어서)
GPT로 작성된 임의의 코드입니다:
import React, { useEffect, useState } from "react";
function BestItems() {
const [bestItems, setBestItems] = useState([]);
const [showItems, setShowItems] = useState(4);
const updateBestItems = () => {
if (window.innerWidth <= 767) setShowItems(1);
else if (window.innerWidth >= 768 && window.innerWidth <= 1199) setShowItems(2);
else setShowItems(4);
};
useEffect(() => {
updateBestItems();
window.addEventListener("resize", updateBestItems);
return () => window.removeEventListener("resize", updateBestItems);
}, []);
useEffect(() => {
getProducts({ page: 1, pageSize: showItems, orderBy: "favorite", keyword: "" }).then((result) => {
if (result) setBestItems(result.list.slice(0, showItems));
});
}, [showItems]);
return (
<div>
{bestItems.map((item) => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}
export default BestItems;| import { getProducts } from "../../../api/products"; | ||
| import Paging from "../../Paging/Paging"; | ||
|
|
||
| export default function ItemPage() { |
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.
(이어서) 최종적으로 ItemPage는 다음과 같이 될 수 있군요 !:
import React from "react";
import BestItems from "./BestItems";
import AllItems from "./AllItems";
export default function ItemPage() {
return (
<div>
<BestItems />
<AllItems />
</div>
);
}| export default function Search({ onSearch }) { | ||
| const debouncedOnSearch = useMemo(() => debounce(onSearch, 500), [onSearch]); | ||
|
|
||
| const handleSearchChange = (e) => { | ||
| const search = e.target.value; | ||
| debouncedOnSearch(search); | ||
| }; |
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.
크으 ~ 디바운스까지 🥺🥺🥺🥺
|
수고하셨습니다 희진님 !! |
요구사항
기본
중고마켓 페이지 주소는 “/items” 입니다.
페이지 주소가 “/items” 일때 상단네비게이션바의 '중고마켓' 버튼의 색상은 “3692FF”입니다.
상단 네비게이션 바는 이전 미션에서 구현한 랜딩 페이지와 동일한 스타일로 만들어 주세요.
전체 상품에서 드롭 다운으로 “최신 순” 또는 “좋아요 순”을 선택해서 정렬을 할 수 있습니다.
'상품 등록하기' 버튼을 누르면 “/additem” 로 이동합니다. ( 빈 페이지 )
카드 데이터는 제공된 백엔드 API 페이지의 GET 메소드인 “/products”를 사용해주세요
미디어 쿼리를 사용하여 반응형 view 마다 물품 개수를 다르게 보여줍니다 (서버로 요청하는 값은 동일)
베스트 상품
Desktop : 4개 보이기
Tablet : 2개 보이기
Mobile : 1개 보이기
전체 상품
Desktop : 12개 보이기
Tablet : 6개 보이기
Mobile : 4개 보이기
심화
주요 변경사항
스크린샷
멘토에게