리액트 무한 스크롤 라이브러리 사용해보기

react-infinite-scroller

위 라이브러리를 사용하여 리액트에서 무한 스크롤을 사용해보자.

1
2
3
4
npm i react-infinite-scroller

# typeScript를 사용한다면 추가
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 [loading, setLoading] = useState(false);
const [error, setError] = useState(null);

function handleLoadMore() {
console.log("more load!");
}

// if (loading) {
// return <div>Loading ...</div>;
// }

if (error) {
return <div>Error: {error}</div>;
}

useEffect(() => {
fetch(Markdown)
.then((res) => res.text())
.then((data) => setMarkdown(data));
}, [markdown]);

useEffect(() => {
// setLoading(true);
try {
setData(customAssetList);
// setLoading(false);
} catch (error) {
setError(error);
// setLoading(false);
}
});

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초 후에 이벤트를 캐치하도록 구현

댓글 공유

  • page 1 of 1

loco9939

author.bio


author.job