useEffect / useState 사용하면서 점점 어려워지는 리액트
허심탄회한 코드 리뷰 남겨보면서 리마인드 해봅니다.
이번 미션은 페이지에 api 가져오고 페이지 네이션까지 해야 했다.
점점 하기 싫어지는 공부단계
하지만 꼭 알아야는 개념이기 때문에
꾸역꾸역 해봅니다.
1. 스위치문 변경
const getPageSize = () => {
const width = window.innerWidth;
if (width < 768) {
// Mobile viewport
return 4;
} else if (width < 1200) {
// Tablet viewport
return 6;
} else {
// Desktop viewport
return 10;
}
};
if문을 활용해서 사이즈 변경 시 상품을 보여주는 값을 다르게 지정했다.
const getPageSize = () => {
const width = window.innerWidth;
switch (true) {
case (width < 768):
// Mobile viewport
return 4;
case (width < 1200):
// Tablet viewport
return 6;
default:
// Desktop viewport
return 10;
}
};
멘토님께서 이렇게 해야 깔끔하고 보기 좋다고 하셨다.
스위치문을 잘 써봐야겠다.
2. 불필요한 state 생략 / 상수화 관리
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(getPageSize());
const [totalPageNum, setTotalPageNum] = useState(0);
const [menuOpen, setMenuOpen] = useState(false);
const [menuLabel, setMenuLabel] = useState('최신순');
menuOpen, menuLabel을 각각 넣어서 state 값을 관리했다.
const [orderBy, setOrderBy] = useState('recent'); // 하나의 상태로 관리
return (
...
<button onClick={toggleMenu} className="dropdown-toggle" type="button">
{orderBy === 'recent' ? "최신순" : "좋아요순"}
</button>
...
)
orderBy 하나로 상태값을 변경할 수 있다.
혹은
const SORT_MENU_INFO = {
RECENT: {
label: '최신순',
orderLabel: 'recent'
},
FAVORITE: {
label: '좋아요순',
orderLabel: 'favorite'
}
}
// 접근 예시
const [menuLabel, setMenuLabel] = useState(SORT_MENU_INFO.RECENT.label));
const [orderBy, setOrderBy] = useState(SORT_MENU_INFO.RECENT.orderLabel);
const handleNewestClick = () => {
setMenuLabel(SORT_MENU_INFO.RECENT.label);
setMenuOpen(false);
setOrderBy(SORT_MENU_INFO.RECENT.orderLabel);
};
요렇게 '최신순' / '좋아요 순'이나 'recent' / 'favorit' 같은 항목들은
컴포넌트 내에서 반복적으로 사용하기도 하고, 변하지 않는 항목들이기 때문에 상수화하여
관리하면 유지보수에 많은 도움이 된다.
3. 반복되는 리스트는 map 활용
const handleNewestClick = () => {
setMenuLabel('최신순');
setMenuOpen(false);
setOrderBy('recent');
};
const handleFavoriteCountClick = () => {
setMenuLabel('좋아요순');
setMenuOpen(false);
setOrderBy('favorite');
};
요렇게 반복되는 리스트의 경우에도 map을 사용할 수 있다고 한다.
const handleSortMenuClick = (sortMenu) => {
setMenuLabel(sortMenu.label);
setMenuOpen(false);
setOrderBy(sortMenu.orderLabel);
}
<ul className={`dropdown-menu ${menuOpen ? 'open' : ''}`}>
{Object.entries(SORT_MENU_INFO).map(([key, value]) => {
return (
<li key={key}>
<button
onClick={() => handleSortMenuClick(value)}
className="dropdown-item"
>
{value.label}
</button>
</li>
);
})}
</ul>
덕분에 코드 반복 사용을 줄였다.
4. pagination 에는 a 태그 말고 button을 사용할 것
return (
<ul className="pagination">
<li className="prev">
<a className="page-link"
disabled={activePageNum === 1}
onClick={() => onPageChange(activePageNum - 1)}
href="#none" title='이전'></a>
</li>
{pages.map((page) => (
<li>
<a href="#none"
key={page}
className={`page-link ${
activePageNum === page ? "on" : ""
}`}
onClick={() => onPageChange(page)}
>{page}</a>
</li>
))}
<li className="next">
<a className="page-link" disabled={activePageNum === totalPageNum}
onClick={() => onPageChange(activePageNum + 1)} href="#none" title='다음'></a>
</li>
</ul>
);
}
퍼블리싱 하면서 습관적으로 a태그를 많이 사용하는데
페이지 이동이 아닌 경우는 버튼 태그를 추천하셨다.
<ul className="pagination">
<li>
<button
className="prev page-link"
disabled={activePageNum === 1}
onClick={() => onPageChange(activePageNum - 1)}
title="이전"></button>
</li>
{pages.map(page => (
<li>
<button
key={page}
className={`page-link ${activePageNum === page ? 'on' : ''}`}
onClick={() => onPageChange(page)}>
{page}
</button>
</li>
))}
<li>
<button
className="page-link next"
disabled={activePageNum === totalPageNum}
onClick={() => onPageChange(activePageNum + 1)}
title="다음"></button>
</li>
</ul>
깔끔해진 버튼들...
이렇게 미션 코드 리뷰를 또 마무리 했다.
솔직히 모든 개념을 다 마스터 하진 못했지만
반복 사용하면서 언젠가는 안보고도 술술 클린코드가 써내려가지길
바래본다.
어설픈 리뷰일진 모르지만
이렇게 조금이라도 기록하면서
리마인드를 한다.
점점 기록하는 스킬도 좋아지는 나를 기대해보며...
리액트에서 배열을 렌더링할 때 key를 써야 하는 이유 (0) | 2024.06.29 |
---|---|
리액트 Virtual DOM (0) | 2024.06.29 |
HTTP 메소드 (0) | 2024.06.21 |
렉시컬 스코프 (0) | 2024.06.21 |
리액트 명령어 정리 (0) | 2024.06.19 |