리액트 무한 스크롤 라이브러리 사용해보기
react-infinite-scroller
위 라이브러리를 사용하여 리액트에서 무한 스크롤을 사용해보자.
1 2 3 4
| npm i react-infinite-scroller
npm i --save-dev @types/react-infinite-scroller
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| import { useEffect, useState } from "react"; import InfiniteScroll from "react-infinite-scroller";
function App() { const [data, setData] = useState<{ label: string }[]>([]); const [error, setError] = useState(null);
function handleLoadMore() { console.log("more load!"); }
if (error) { return <div>Error: {error}</div>; }
useEffect(() => { fetch(Markdown) .then((res) => res.text()) .then((data) => setMarkdown(data)); }, [markdown]);
useEffect(() => { try { setData(customAssetList); } catch (error) { setError(error); } });
return ( <div className="App"> <InfiniteScroll // 사용자에 의해 더 많은 아이템이 요청될 때 실행하는 콜백함수 loadMore={handleLoadMore} // 이벤트 리스너를 component의 부모요소에 추가 useWindow={false} // 해당 아이템을 감싸는 태그 element="article" className="index" // loading 중일 때 보여줄 요소 loader={ <div className="loader" key={0}> Loading ... </div> } > {data.map((da, index) => ( <div key={index}> <h3>종목: {index + 1}</h3> <p>{da.label}</p> </div> ))} </InfiniteScroll> </div> ); }
|
- data를 state로 관리해주고 useEffect 훅을 사용하여 처음 화면이 렌더링 될 때, loading 상태를 변경시키고 data를 업데이트한다.
- InfiniteScroll 컴포넌트는 내부적으로 loading 상태일 때를 관리하고 있어 개발자가 따로 loading state를 가질 필요가 없다.
검색 기능 활성화 시키기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import debounce from "lodash/debounce";
function App() { const [data, setData] = useState<{ label: string }[]>([]); const [searchValue, setSearchValue] = useState(""); const [filteredData, setFilteredData] = useState<{ label: string }[]>([]);
const handleSearchValue = debounce((value) => { setSearchValue(value); const filtered = data.filter((item) => item.label.includes(value)); setFilteredData(filtered); }, 300);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => { const value = e.currentTarget.value; handleSearchValue(value); };
return ( <div> <InfiniteScroll loadMore={handleLoadMore} useWindow={false} element="article" className="index" loader={ <div className="loader" key={3}> Loading ... </div> } > {searchValue !== "" ? filteredData.map((item, index) => ( <div key={index}> <h3>종목: {index + 1}</h3> <p>{item.label}</p> </div> )) : data.map((da, index) => ( <div key={index}> <h3>종목: {index + 1}</h3> <p>{da.label}</p> </div> ))} </InfiniteScroll> </div> ); }
|
- handleChange를 onChange 이벤트 핸들러로 등록하여 change 이벤트가 발생할 때 마다 검색값으로 필터된 데이터를 보여준다.
- onChange 이벤트가 너무 많이 발생하면 1만개의 데이터가 자주 렌더링 되므로 성능에 문제가 있을 수 있어 debounce를 사용하여 이벤트가 끝난 후 0.3초 후에 이벤트를 캐치하도록 구현