react-infinite-scroll-component
infinite scroll을 예전에 구현했을 땐 직접 구현했었는데 회사에서 라이브러리를 사용했기 때문에 이것에 대한 사용방법을 익히고 다시한번 예전에 구현했던 코드를 상기시키는 시간을 가져보려 한다
react-infinite-scroll-component
// 공식 문서 예시 1
import React from "react";
import { render } from "react-dom";
import InfiniteScroll from "react-infinite-scroll-component";
const style = {
height: 30,
border: "1px solid green",
margin: 6,
padding: 8
};
class App extends React.Component {
state = {
items: Array.from({ length: 20 })
};
fetchMoreData = () => {
// a fake async api call like which sends
// 20 more records in 1.5 secs
setTimeout(() => {
this.setState({
items: this.state.items.concat(Array.from({ length: 20 }))
});
}, 1500);
};
render() {
return (
<div>
<h1>demo: react-infinite-scroll-component</h1>
<hr />
<InfiniteScroll
dataLength={this.state.items.length} // 반복되는 컴포넌트의 개수
next={this.fetchMoreData} // 스크롤이 바닥에 닿으면 데이터를 더 불러오는 함수
hasMore={true} // 추가 데이터 유무
loader={<h4>Loading...</h4>} // 로딩스피너
>
{this.state.items.map((i, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
</div>
);
}
}
render(<App />, document.getElementById("root"));
// 공식 문서 예시 2
<div
id="scrollableDiv"
style={{
height: 300,
overflow: 'auto',
display: 'flex',
flexDirection: 'column-reverse',
}}
>
{/*Put the scroll bar always on the bottom*/}
<InfiniteScroll
dataLength={this.state.items.length}
next={this.fetchMoreData}
style={{ display: 'flex', flexDirection: 'column-reverse' }} //To put endMessage and loader to the top.
inverse={true} //
hasMore={true}
loader={<h4>Loading...</h4>}
scrollableTarget="scrollableDiv"
>
{this.state.items.map((_, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
</div>
-
scrollableTarget : 여러 컨텐츠 리스트에 의해 스크롤이 생기는 엘리먼츠
- 원하는 엘리먼츠의 id를 입력해서 지정 가능
- document.body로 설정하려면 scrollableTarget, height 모두 설정하지 않으면 document.body를 기준으로 함
-
동작 원리 : height prop을 제공하지 않으면 기본적으로 scrollableTarget(document.body)의 맨 끝에 닿으면 next함수가 실행되면서 추가 데이터를 요청하는 구조
기존에 직접 구현하던 방식
browser Web API
- 1) document.documentElement.scrollTop : 전체화면 중 현재 화면의 위치
- 2) window.innerHeight : 현재 화면의 전체 높이
- 3) document.documentElement.scrollHeight : 전체화면의 전체 높이
- 스크롤을 내리면 현재 화면의 위치가 바뀜(document.documentElement.scrollTop)
- 스크롤을 최대로 내리면 현재화면의 위치 + 현재화면의 높이 = 전체화면의 높이가 됨
- 이때 새로운 페이지 데이터를 요청
- document.documentElement.scrollTop + window.innerHeight + 300 >= document.documentElement.scrollHeight
- 최대로 내리기 전에 요청을 하면 더 좋은 사용자 경험을 줄 수 있음
구현 예시
// useInfiniteScroll.ts
export function useInfiniteScroll() {
const [page, setPage] = useState(1);
function handleScroll() {
if (
document.documentElement.scrollTop + window.innerHeight + 300 >=
document.documentElement.scrollHeight
) {
setPage((p) => p + 1);
}
}
useEffect(() => {
window.addEventListener("scroll", handleScroll);
}, []);
return page;
}
// Movie.tsx
import { movieApi } from "../api/axiosApi";
const Movie = () => {
const [movies, setMovies] = useState<Movie[]>([]);
const page = useInfiniteScroll();
useEffect(() => {
movieApi
.nowPlaying(page)
.then((res) => {
const {
data: { results },
} = res;
setMovies((prev) => [...prev, ...results]);
})
.catch((err) => console.error(err));
}, [page]);
return (
<main>
{movies.map((movie) => {
return (
<div key={movie.id}>
<h3>{movie.title}</h3>
<p>{movie.overview}</p>
</div>
);
})}
</main>
);
};
export default Movie;
- 스크롤 이벤트로 인한 페이지 요청 시 한번에 여러번 요청이 될 가능성이 높으므로 로딩 상태에선 요청을 막는 로직이 필요함(예시엔 구현이 안되어 있음)
- 향후 react-query를 사용하여 loading 동안 요청을 하지 않도록 할 예정
참고
- https://github.com/ankeetmaini/react-infinite-scroll-component
- https://github.com/TaehwanGo/playground/commit/4103fcd0a90da921e90c75726aa12665624f698f
Author And Source
이 문제에 관하여(react-infinite-scroll-component), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gth1123/react-infinite-scroll-component저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)