React 강석준 sprint5#74
Hidden character warning
Conversation
/src를 @로 alias 설정
eslint와 충돌 해결 설정 및 tailwindcss plugin 적용
수정 전: 전체 상품에서 정렬 후 앞 부분을 베스트 상품으로 저장하는 방식 수정 후: 쿼리스트링으로 최소한의 데이터만 따로 불러와 저장하는 방식
|
스프리트 미션 하시느라 수고 많으셨어요. |
|
크으... 깃 로그가 언제나 깔끔하십니다 👍 |
| <Header /> | ||
| <div className="flex h-135 w-full items-end justify-center bg-blue-100"> | ||
| <PrimaryCard {...PRIMARY_CARDS[0]} /> | ||
| </div> | ||
| <div className="flex flex-col items-center pb-34.5"> | ||
| {FEATURE_CARDS.map((card) => ( | ||
| <div key={card.id} className="p-34.5"> | ||
| <FeatureCard {...card} /> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| <div className="flex h-135 w-full items-end justify-center bg-blue-100"> | ||
| <PrimaryCard {...PRIMARY_CARDS[1]} /> | ||
| </div> | ||
| <Footer /> |
There was a problem hiding this comment.
Layout(Header, Footer)을 공통적으로 적용할 방법은 없을까요?
각 페이지 별로 Layout을 계속 불러오지 않고, react-router-dom을 이용해서 layout을 조건에 따라(로그인일 경우 X) 공통적으로 출력하는 방법이 없을까요?
There was a problem hiding this comment.
(추가로) react-routes-dom에서 레이아웃을 설정할 수 있어요. 😊
Consider: 판다마켓 초기에 작성한 로그인과 회원가입과 같은 페이지는 Header가 없는 디자인이예요. 지금과 같이 한다면 특정 페이지의 레이아웃을 조정하기 어려울거예요 !
Routes에서 element를 지정하여 중첩 레이아웃을 사용할 수 있으니 참고해서 설계해보세요 😊
tl;dr
// App.tsx
<Routes>
<Route path="/" element={<Main />}> // 중첩 라우팅
<Route path="user-management" element={<UserManagement />} />
<Route path="child-management" element={<ChildManagement />} />
</Route>
<Route path="/login" element={<Login />} />
</Routes>
// Main.tsx
<MainWrapper>
<MainMenu />
<Outlet /> // children과 같은 효과 ! ✨
</MainWrapper>| export const getItems = async ( | ||
| page, | ||
| pageSize, | ||
| orderBy = "recent", | ||
| keyword = null, | ||
| ) => { | ||
| const baseURL = "https://panda-market-api.vercel.app/products/"; |
There was a problem hiding this comment.
(제안) 해당 변수는 다른 api 함수에서 사용될 수도 있으므로 함수 바깥에 선언하는게 더욱 활용성이 좋겠군요 !
| export const getItems = async ( | |
| page, | |
| pageSize, | |
| orderBy = "recent", | |
| keyword = null, | |
| ) => { | |
| const baseURL = "https://panda-market-api.vercel.app/products/"; | |
| const baseURL = "https://panda-market-api.vercel.app/products/"; | |
| export const getItems = async ( | |
| page, | |
| pageSize, | |
| orderBy = "recent", | |
| keyword = null, | |
| ) => { | |
There was a problem hiding this comment.
(더 나아가서) base URL은 환경 변수에 저장하시는게 좋습니다!
환경 변수(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>
왜 환경 변수에 저장해야 하나요?
개발(dev), 테스트(test), 실제 사용(prod) 등 다양한 환경에서 앱을 운영하게 되는 경우, 각 환경에 따라 다른 base URL을 사용해야 할 수 있습니다. 만약 코드 내에 하드코딩되어 있다면, 각 환경에 맞춰 앱을 배포할 때마다 코드를 변경해야 하며, 이는 매우 번거로운 작업이 됩니다. 하지만, 환경 변수를 .env.production, .env.development, .env.test와 같이 설정해두었다면, 코드에서는 단지 다음과 같이 적용하기만 하면 됩니다.
const apiUrl = `${process.env.REACT_APP_BASE_URL}/api`;
이러한 방식으로 환경 변수를 사용하면, 배포 환경에 따라 쉽게 URL을 변경할 수 있으며, 코드의 가독성과 유지보수성도 개선됩니다.
실제 코드 응용과 관련해서는 다음 한글 아티클을 참고해보세요! => 보러가기
| const params = new URLSearchParams({ | ||
| page: page, | ||
| pageSize: pageSize, | ||
| orderBy: orderBy, | ||
| }); |
There was a problem hiding this comment.
크으 ~ URLSearchParams를 사용하셨군요 ! 👍
쿼리를 작성할 때 정말 편하게 사용할 수 있도록 도와주지요 ~
| const response = await fetch(requrl, { | ||
| method: "GET", | ||
| }); |
There was a problem hiding this comment.
axios를 사용해보는건 어떨까요?(제안/선택)
fetch 모듈을 잘 만든다는 것은 어렵습니다. 다음 사항들을 고려해볼 수 있어요:
- 만약
get이 아닌 메써드(post,patch,delete등)일 경우는 어떻게 처리할 수 있을까요? query와body가 필요할 때는 어떻게 처리 할 수 있을까요?- 로그인 인가를 위한 토큰을 request 전에 자동으로 삽입할 수는 없을까요? (인증/인가를 자동으로 할 수 없을까요?)
- 처음 한 번에 Base URL을 지정할 수는 없을까요?
- Base URL을 사용하다가 타 Domain에 보내야 될 때는 어떻게 할 수 있을까요?
이 모든 요구사항들을 '잘 만든다는 것'은 어려워요. 따라서 이 모든걸 만들어진fetch모듈을 사용해보고 후에fetch모듈을 만들어 보는 것도 좋은 학습 방법이 될 수 있어요.
- Base URL을 사용하다가 타 Domain에 보내야 될 때는 어떻게 할 수 있을까요?
어떻게 세팅하면 될까? 🤔
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}`)딱 보니. 마이그레이션도 정말 쉽게 할 수 있겠죠? 😊
| try { | ||
| const res = await getItems(page, pageSize, orderBy); | ||
| setItems(res.list); | ||
| } catch (error) { | ||
| console.error("전체 상품 불러오기 실패", error); | ||
| } finally { | ||
| setItemsLoading(false); | ||
| } |
| } catch (error) { | ||
| console.error("전체 상품 불러오기 실패", error); | ||
| } finally { |
There was a problem hiding this comment.
UI 계층에서 에러 발생 시 사용자 피드백도 함께 해주면 어떨까요?
| } catch (error) { | |
| console.error("전체 상품 불러오기 실패", error); | |
| } finally { | |
| } catch (error) { | |
| console.error("전체 상품 불러오기 실패", error); | |
| alert(error.message) | |
| } finally { |
설치 필요 없지.. 대부분의 브라우저와 디바이스에서 사용 가능하지...
alert는 정말 훌륭한 사용자 피드백 브라우저 API 입니다 !
| export const BREAK_POINTS = { | ||
| tablet: 768, | ||
| desktop: 1280, | ||
| }; |
| desktop: 1280, | ||
| }; | ||
|
|
||
| function useResponsiveLayout({ onLayoutChange }) { |
There was a problem hiding this comment.
적절한 훅입니다 ! 👍👍
많이 사용될 것 같은데, 적절히 커스텀 훅을 만드셨군요 👍
|
어우 ~ 훌륭합니다 석준님. |
요구사항
기본
중고마켓
중고마켓 반응형
심화
결과 - 페이지 바로가기
멘토에게