-
Notifications
You must be signed in to change notification settings - Fork 42
[김동희] Sprint5 #224
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-\uAE40\uB3D9\uD76C-sprint5"
[김동희] Sprint5 #224
Conversation
[Fix] delete merged branch github action
랜딩 페이지를 React로 새로 구현
로고 컴포넌트 추가와 함께, 기존 로고 이미지를 로고 컴포넌트로 대체
로그인 페이지 및 회원가입 페이지 추가
switch문에 대한 들여쓰기 rule 추가
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.
수고하셨습니다!
리액트 첫 미션인데도 커스텀 훅도 잘 사용하시고, 꼼꼼함이 돋보이는 작업이었네요 👍
조금만 다듬어보면 좋을것같습니다!
주요 리뷰 포인트
- styled components props 한번만 받아오고 css 함수 안에서 스타일 묶어서 처리하기
- 핵심 로직을 먼저 작성해보기
- 지나친 축약 / 의미를 알 수 없는 네이밍 사용 지양하기
- 공용 컴포넌트 관리 방식 제안
- 상수는 컴포넌트 외부에서 관리하기
- optional chaining 활용법
- 커스텀 훅 로직 분리
- SortSelect 컴포넌트 불필요한 props 없애기
- 리턴문에서 jsx 직접적으로 반환하기
color: ${({ theme }) => theme.colors.gray100}; | ||
background-color: ${({ theme }) => theme.colors.primary100}; | ||
cursor: pointer; | ||
|
||
&:hover { | ||
background-color: ${({ theme }) => theme.colors.primary200}; | ||
} | ||
|
||
&:active { | ||
background-color: ${({ theme }) => theme.colors.primary300}; | ||
} |
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.
color: ${({ theme }) => theme.colors.gray100}; | |
background-color: ${({ theme }) => theme.colors.primary100}; | |
cursor: pointer; | |
&:hover { | |
background-color: ${({ theme }) => theme.colors.primary200}; | |
} | |
&:active { | |
background-color: ${({ theme }) => theme.colors.primary300}; | |
} | |
${({ theme }) => css` | |
color: ${theme.colors.gray100}; | |
background-color: ${theme.colors.primary100}; | |
cursor: pointer; | |
&:hover { | |
background-color: ${theme.colors.primary200}; | |
} | |
&:active { | |
background-color: ${theme.colors.primary300}; | |
} | |
`} |
이렇게 theme을 한 번만 받아와서 css 함수 안에서 모든 스타일 규칙을 정의할 수 있게 수정해보시면, theme prop을 한번만 접근하면되고 관련된 스타일이 하나의 블록으로 묶이기때문에 가독성 또한 좋아질 수 있겠죠? :)
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.
해당 파일의 핵심 로직은 styled component가 아닌 Favorite 컴포넌트 구성 로직이기때문에, 순서를 바꾸시는게 좋을 것 같아요.
항상 핵심 로직을 먼저 작성하는 습관을 들여봅시다 :)
const FeatureList = () => { | ||
return ( | ||
<FeatureListWrapper> | ||
{featureList.map((e) => ( |
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.
여기서 e는 어떤 단어를 축약한것인가요?
이벤트 핸들러 함수가 아니니까 이벤트 객체는 아니겠죠?
지나친 축약 / 의미를 알 수 없는 네이밍은 지양해봅시다! :)
<StyledLinkToItemsButton | ||
link={'/items'} | ||
ariaLabel={'중고 마켓 거래 리스트 보러가기'} | ||
type={'pill'} | ||
> |
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.
공용 컴포넌트인 Button 컴포넌트를 확장하기 위한 목적으로 styled components를 쓰고 있는데, 이러한 방식은 일관성과 유지보수 측면에서 그닥 좋지 않습니다.
이유는, 모든 버튼 스타일링이 Button 컴포넌트 내부에서 관리되고 있다면
새로운 버튼 스타일을 추가하거나 수정할 일이 있을때 Button 컴포넌트만 수정하면되는데, 이런식으로 버튼을 확장해서 만들어놓은 케이스를 찾아서 수정해야하는 번거로움이 있기 때문입니다.
Button 컴포넌트를 variant 기반으로 관리하거나, 일부 스타일링을 오버라이드하는 방식은 어떨까요? :)
variant 기반으로 관리하는 방식의 예시를 보여드릴게요!
const StyledButton = styled.button`
/* Variant styles */
${({ variant }) => {
switch (variant) {
case 'link-to-items':
return css`
width: 240px;
height: 48px;
font-size: 1.125rem;
`;
default:
return css``;
}
}}
`;
const StyledLoginButton = styled(Button)` | ||
width: 128px; | ||
height: 48px; | ||
font-size: 1em; | ||
`; |
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.
여기서도 마찬가지! 해당 코드를 일관성, 유지보수 측면에서 더 효율적인 방식으로 개선한다면, 어떻게 해볼까 고민해볼까요? 위 코멘트 참고해보시고 리팩토링해보세요! :)
const [startNumber, setStartNumber] = useState(1); | ||
const [currentNumber, setCurrentNumber] = useState(1); | ||
const { all: pageSize } = PRODUCTS_PAGE_SIZES[deviceType]; | ||
const maxPage = Math.ceil(total / pageSize); | ||
|
||
const pageNumbersToShow = Array.from( | ||
{ length: 5 }, | ||
(_, i) => startNumber + i | ||
); | ||
|
||
const handlePrevGroupClick = () => { | ||
if (startNumber > 1) { | ||
const newStart = startNumber - 5; | ||
setStartNumber(newStart); | ||
setCurrentNumber(newStart); | ||
setPage(newStart); | ||
} | ||
}; | ||
|
||
const handleNextGroupClick = () => { | ||
if (startNumber + 4 < maxPage) { | ||
const newStart = startNumber + 5; | ||
setStartNumber(newStart); | ||
setCurrentNumber(newStart); | ||
setPage(newStart); | ||
} | ||
}; | ||
|
||
const handlePageClick = (e) => { | ||
setPage(e.target.value); | ||
setCurrentNumber(Number(e.target.value)); | ||
}; |
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.
페이지네이션 로직은 특성상 여러 페이지에서 재사용될 수 있겠죠?
재사용 가능한 로직은 커스텀 훅으로, UI는 컴포넌트로 분리해주면 어떨까요?
const handleSelect = (option) => { | ||
setSelectedLabel(option.label); | ||
setIsOpen(false); | ||
handleOptionSelect && handleOptionSelect(option.value); |
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.
이런 경우에도 optional chaining 사용해주면 좀 더 깔끔해져요!
handleOptionSelect && handleOptionSelect(option.value); | |
handleOptionSelect?.(option.value); |
options, | ||
defaultValue, | ||
onSelect: handleOptionSelect, | ||
deviceType, |
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.
deviceType은 SortSelect 컴포넌트에서 props로 전달받기보다는 현재 디바이스 타입을 계산하는 로직만 분리해 커스텀 훅을 만들고, 해당 컴포넌트에서 직접 사용해주는 편이 더 명료할것같네요! :)
{isOpen ? ( | ||
<StyledOptionsLists> | ||
{options.map((option) => ( | ||
<li key={option.value}> | ||
<StyledOptionButton | ||
onClick={() => handleSelect(option)} | ||
$isSelected={selectedLabel === option.label} | ||
> | ||
{option.label} | ||
</StyledOptionButton> | ||
</li> | ||
))} | ||
</StyledOptionsLists> | ||
) : ( | ||
<></> | ||
)} |
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.
반대의 경우 fragment를 반환하고있는데, 일부러 반환할 필요 없습니다.
{isOpen ? ( | |
<StyledOptionsLists> | |
{options.map((option) => ( | |
<li key={option.value}> | |
<StyledOptionButton | |
onClick={() => handleSelect(option)} | |
$isSelected={selectedLabel === option.label} | |
> | |
{option.label} | |
</StyledOptionButton> | |
</li> | |
))} | |
</StyledOptionsLists> | |
) : ( | |
<></> | |
)} | |
{isOpen && ( | |
<StyledOptionsLists> | |
{options.map((option) => ( | |
<li key={option.value}> | |
<StyledOptionButton | |
onClick={() => handleSelect(option)} | |
$isSelected={selectedLabel === option.label} | |
> | |
{option.label} | |
</StyledOptionButton> | |
</li> | |
))} | |
</StyledOptionsLists> | |
)} |
setOrder(selectedOrder); | ||
}; | ||
|
||
const result = |
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.
아까도 이런 패턴을 쓰신걸 본것같은데,
따로 변수에 담아 리턴할 필요없이 리턴문에서 jsx을 바로 리턴해주세요!
요구사항
기본
중고마켓
중고마켓 반응형
베스트 상품
전체 상품
심화
주요 변경사항
스크린샷
멘토에게