function myThrottle(callback, wait = 300) {
let timer;
return () => {
if (!timer) {
timer = setTimeout(() => {
timer = null;
callback();
}, wait);
}
};
}
const onScroll = e => {
const value = window.scrollY;
setIsScroll(value > 50);
setIsHeaderClick(false);
};
useEffect(() => {
window.addEventListener('scroll', myThrottle(onScroll));
return () => {
window.removeEventListener('scroll', myThrottle(onScroll));
};
}, []);
분명 언마운트 될 때 removeEventListener로 cleanup을 시켜도 myThrottle
로 인해 다른 페이지에서도 스크롤 이벤트가 계속 동작되어 그 안에서 setState로 인해 업데이트가 되면서 생기는 오류였다.
처음에는 setTimeout
으로 인한 오류라 생각되어 timer 변수
를 전역으로 빼내고 언마운트시 clearTimeout(timer)
을 이용했지만 여전히 오류가 발생했다.
let timer;
function myThrottle(callback, wait = 300) {
return () => {
if (!timer) {
timer = setTimeout(() => {
timer = null;
callback();
}, wait);
}
};
}
useEffect(() => {
window.addEventListener('scroll', myThrottle(onScroll));
return () => {
clearTimout(timer);
window.removeEventListener('scroll', myThrottle(onScroll));
};
}, []);
고민해보니 클로저로 인해 addEventListener에서 생성된 실행컨텍스트가 아직 남아
있었고 removeEventListener에서는 엉뚱한 실행 컨텍스트를 제거
해서 생기는 오류 같았다.
이를 고치기 위해 const throttle = myThrottle(onScroll, 300);
로 변수에 할당하여 언마운트 시 해당 실행 컨텍스트를 없애주는 방식으로 변경하여 에러가 뜨지 않는 것을 확인 할 수 있었다.
function myThrottle(callback, wait = 300) {
let timer;
return () => {
if (!timer) {
timer = setTimeout(() => {
timer = null;
callback();
}, wait);
}
};
}
const onScroll = e => {
console.log('hi');
const value = window.scrollY;
setIsScroll(value > 50);
setIsHeaderClick(false);
};
useEffect(() => {
const throttle = myThrottle(onScroll, 300);
window.addEventListener('scroll', throttle);
return () => {
window.removeEventListener('scroll', throttle);
};
}, []);
기존에 리스트의 전체를 보여주는 방식에서 페이지네이션을 구현하여 원하는 갯수만큼 보여주는 방식으로 변경하였다.
이를 위해서는 현재 페이지를 관리하는 currentPage state
, 페이지마다 보여줄 갯수를 관리하는 listPerPage state
를 이용하였다.
그리고 slice() 메서드
를 이용하여 보여줄 숙소 리스트를 조절하였다.
const [currentPage, setCurrentPage] = useState(1);
const [listPerPage, setPerPage] = useState(5);
const idxOfLastList = currentPage * listPerPage;
const idxOfFirstList = idxOfLastList - listPerPage;
const currentAccomodationList = filteredAccomodationList.slice(idxOfFirstList, idxOfLastList);
const changePage = pageNum => {
setCurrentPage(pageNum);
window.scrollTo(0, 0);
};
PaginationContainer 컴포넌트
는 페이지 번호를 생성하는 역할을 한다.
추후에 전역으로 props를 관리하게 되면 해당 컴포넌트에서 페이지관련 로직을 수행하게끔 변경할 예정이다.
function PaginationContainer({
totalAccomodationList,
listPerPage,
accomodationList,
idxOfFirstList,
changePage,
currentPage,
}) {
const pageNumbers = Array.from(
new Array(Math.ceil(totalAccomodationList.length / listPerPage)),
(v, i) => i + 1,
);
return (
<Pagination
pageNumbers={pageNumbers}
totalListLength={totalAccomodationList.length}
listPerPage={listPerPage}
accomodationList={accomodationList}
idxOfFirstList={idxOfFirstList}
changePage={changePage}
currentPage={currentPage}
/>
);
}
export default PaginationContainer;
Pagination 컴포넌트
에서는 해당 Props를 받아 화면에 보여지게하였다.
<section css={paginationPaddingContainer}>
<div css={paginationContainer}>
<ul css={pageWrap}>
{currentPage === firstPageNum ? (
<li css={pageBtnDisable}>❮</li>
) : (
<li css={pageBtn} onClick={() => changePage(currentPage - 1)}>
❮
</li>
)}
{pageNumbers.map((pageNum, idx) => (
<PageItem
pageNum={pageNum}
key={idx}
changePage={changePage}
isCurrentPage={pageNum === currentPage}
/>
))}
{currentPage === lastPageNum ? (
<li css={pageBtnDisable}>❯</li>
) : (
<li css={pageBtn} onClick={() => changePage(currentPage + 1)}>
❯
</li>
)}
</ul>
<div css={totalPage}>{`총 ${totalListLength}개의 숙소 중 ${idxOfFirstList + 1} ~ ${
idxOfFirstList + accomodationList.length
}번째 숙소`}</div>
</div>
</section>
현재는 모든 페이지번호가 보이며 페이지가 많아질 시 ...방식을 구현하지 않았기 때문에 추후에 수정해야한다.