-
Notifications
You must be signed in to change notification settings - Fork 27
[양재영] sprint 5 #99
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
The head ref may contain hidden characters: "React-\uC591\uC7AC\uC601-sprint5"
[양재영] sprint 5 #99
Conversation
{isMobile ? ( | ||
<div className="total-products-container"> | ||
<div className="products-title-mobile"> | ||
<h1 className="products-title">전체 상품</h1> | ||
<Link to="/additem" className="add-item-button"> | ||
상품 등록하기 | ||
</Link> | ||
</div> | ||
<div className="total-products-content"> | ||
<div className="total-products-content-input"> | ||
<img src={searchIcon} alt="검색 아이콘" /> | ||
<input | ||
type="text" | ||
placeholder="검색할 상품을 입력해주세요" | ||
value={keyword} | ||
onChange={onKeywordChange} | ||
/> | ||
</div> | ||
<select onChange={onOrderChange} value={orderBy}> | ||
<option value="recent">최신순</option> | ||
<option value="favorite">좋아요순</option> | ||
</select> | ||
</div> | ||
</div> | ||
) : null} |
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.
질문에 올린 select 이미지 설정법에 관한 useMediaQuery 로 모바일 사이즈일 때 구조 변경 코드줄 / 반응형 CSS 는 './ItemsPage.css'
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.
전체상품의 orderBy 에 따른 최신순 좋아요순을 select와 option을 사용 하였는데 반응형 모바일 사이즈에서 이미지 변경이 궁금합니다.
답변을 드리고 싶은데 잘 이해가 안되어서요 🥲
혹시 "select
, option
props
를 전달하여 구성하였다."까지는 이해했는데요. 혹시 select
이미지 설정법이란게 어떤걸 의미하는걸까요 ?
DM 통해서 답변 주시거나 줌 미팅을 통해서도 답변드릴 수 있습니다 !
스프리트 미션 하시느라 수고 많으셨어요. |
export async function getProducts({ | ||
page = 1, | ||
pageSize = 10, | ||
orderBy = "recent", | ||
keyword = "", | ||
}) { |
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.
굿굿! 훌륭합니다 👍
백엔드 요구사항대로 파라메터를 잘 설계하셨네요 👍👍
orderBy = "recent", | ||
keyword = "", | ||
}) { | ||
const params = new URLSearchParams({ page, pageSize, orderBy, keyword }); |
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.
크으 ~ 자바스크립트 임베드 객체인 URLSearchParams
까지 제대로군요 ! 👍
URLSearchParams:
URLSearchParams
인터페이스는 URL의 쿼리 문자열을 대상으로 작업할 수 있는 유틸리티 메서드를 정의합니다.
const response = await fetch( | ||
`https://panda-market-api.vercel.app/products?${params}` | ||
); |
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.
axios를 사용해보는건 어떨까요?(제안/선택)
fetch
모듈을 잘 만든다는 것은 어렵습니다. 다음 사항들을 고려해볼 수 있어요:
- 만약
get
이 아닌 메써드(post
,patch
,delete
등)일 경우는 어떻게 처리할 수 있을까요? query
와body
가 필요할 때는 어떻게 처리 할 수 있을까요?- 로그인 인가를 위한 토큰을 request 전에 자동으로 삽입할 수는 없을까요? (인증/인가를 자동으로 할 수 없을까요?)
- 처음 한 번에 Base URL을 지정할 수는 없을까요?
- Base URL을 사용하다가 타 Domain에 보내야 될 때는 어떻게 할 수 있을까요?
이 모든 요구사항들을 '잘 만든다는 것'은 어려워요. 따라서 이 모든걸 만들어진fetch
모듈을 사용해보고 후에fetch
모듈을 만들어 보는 것도 좋은 학습 방법이 될 수 있어요.
- Base URL을 사용하다가 타 Domain에 보내야 될 때는 어떻게 할 수 있을까요?
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.
어떻게 세팅하면 될까? 🤔
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
인가에 필요한 accessToken
을 localStorage
가 있다면 axios의 인터셉터를 활용할 수 있습니다 !
인터셉터는 혼자 해결해보시는 것을 권장드립니다. 혹시 모르시겠으면 다음 위클리 미션에 질문해주세요. 😊
사용 방법 🚀
사용 방법은 정말 간단해요. 다음과 같이 사용할 수 있습니다:
instance.get(`/user/${userId}`)
딱 보니. 마이그레이션도 정말 쉽게 할 수 있겠죠? 😊
}) { | ||
const params = new URLSearchParams({ page, pageSize, orderBy, keyword }); | ||
const response = await fetch( | ||
`https://panda-market-api.vercel.app/products?${params}` |
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.
https://panda-market-api.vercel.app
는 앞으로도 계속 사용되겠군요 !
이 때 환경 변수로 지정해두시면 편리합니다 !
환경 변수(Environment Variable):
process.env
에 내장되며 앱이 실행될 때 적용할 수 있는 값입니다!
다음과 같이 적용할 수 있습니다:
// .env.development
REACT_APP_BASE_URL="http://localhost:3000"
// .env.production
REACT_APP_BASE_URL="http://myapi.com"
// 사용시
<a href={`${process.env.REACT_APP_BASE_URL}/myroute`}>URL</a>
throw new Error("상품을 불러오는데 실패했습니다"); | ||
} | ||
const data = await response.json(); | ||
return [data.list, data.totalCount]; |
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.
배열 형태로 반환할 필요가 없어보이는군요 ! 🤔
return [data.list, data.totalCount]; | |
return data; |
배열로 반환하게 되면 반환되는 값이 어떤 값인지 유추하기 어려울 것으로 보입니다. 😊
이럴 때는 그냥 백엔드로부터 받은 데이터 그대로 반환해도 무방해보입니다 👍
alt={product.name} | ||
/> | ||
<h3 className="product-name">{product.name}</h3> | ||
<p className="product-price">{product.price.toLocaleString()}원</p> |
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.
<p>
태그는 단락을 나타냅니다 !
HTML <p>
요소는 하나의 문단을 나타냅니다. 시각적인 매체에서, 문단은 보통 인접 블록과의 여백과 첫 줄의 들여쓰기로 구분하지만, HTML에서 문단은 이미지나 입력 폼 등 서로 관련있는 콘텐츠 무엇이나 될 수 있습니다.
예를 들어 다음과 같은 값이 <p>
태그에 적절할 수 있어요 😊:
Geckos are a group of usually small, usually nocturnal lizards. They are found on every continent except Antarctica.
혹은:
헌법재판소는 법관의 자격을 가진 9인의 재판관으로 구성하며, 재판관은 대통령이 임명한다. 선거에 있어서 최고득표자가 2인 이상인 때에는 국회의 재적의원 과반수가 출석한 공개회의에서 다수표를 얻은 자를 당선자로 한다.
useEffect(() => { | ||
async function fetchTotalProducts() { | ||
try { | ||
const [list, count] = await getProducts({ | ||
page, | ||
pageSize: totalCountPerPage, | ||
orderBy, | ||
keyword, | ||
}); | ||
setTotalProducts(list); | ||
setTotalCount(count); | ||
} catch (error) { | ||
setError(error.message); | ||
} | ||
} | ||
|
||
fetchTotalProducts(); | ||
}, [page, orderBy, keyword, totalCountPerPage]); |
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.
굿굿. useEffect
에 적절한 의존성이네요.
fetch
함수도 useEffect
안에서 선언함으로써 리렌더링 시 불필요한 재선언과 스코프도 명확하여 가독성도 챙길 수 있는 코드로 보입니다 👍👍
export const useResponsive = () => { | ||
const isTablet = useMediaQuery({ maxWidth: 1199 }); | ||
const isMobile = useMediaQuery({ maxWidth: 767 }); | ||
|
||
return isMobile ? [1, 4] : isTablet ? [2, 6] : [4, 10]; | ||
}; |
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.
굿굿! 커스텀 훅을 만들어 재사용하셨군요 👍👍
수고하셨습니다 재영님~! 충분히 잘하시고 계십니다. 👍👍 질문에 대해 답변드리지 못해서 염려가 되는데요 ! 궁금하신 사항은 DM 주시면 조속히 답변드리도록 하겠습니다 😊 |
요구사항
기본
중고마켓 페이지 주소는 “/items” 입니다.
페이지 주소가 “/items” 일때 상단네비게이션바의 '중고마켓' 버튼의 색상은 “3692FF”입니다.
상단 네비게이션 바는 이전 미션에서 구현한 랜딩 페이지와 동일한 스타일로 만들어 주세요.
상품 데이터 정보는 https://panda-market-api.vercel.app/docs/#/ 에 명세된 GET 메소드 “/products” 를 사용해주세요.
상품 등록하기' 버튼을 누르면 “/additem” 로 이동합니다. ( 빈 페이지 )
전체 상품에서 드롭 다운으로 “최신 순” 또는 “좋아요 순”을 선택해서 정렬을 할 수 있습니다.
중고마켓 반응형
베스트 상품
전체 상품
심화
주요 변경사항
스크린샷
멘토에게
select
와option
을 사용 하였는데 반응형 모바일 사이즈에서 이미지 변경이 궁금합니다.