๐ฐ React์์ ๋ฌดํ ์คํฌ๋กค์ ์ดํดํ๊ณ ๋ง๋ค ์์๋ค.
โ ๋ฌดํ ์คํฌ๋กค
์น์ฌ์ดํธ์์ ์ฌ์ฉ์๋ค์๊ฒ ํธ๋ฆฌํ ๊ธ๋ชฉ๋ก์ ์ ๊ณตํ๋ ค๋ ๊ธฐ์กด์๋ ํ์ด์ง๋ค์ด์ ์ ์ด์ฉํ์ฌ ์ ๊ณตํ์๋ค.
ํ์ง๋ง ํ์ด์ง๋ค์ด์ ์ ์ฌ์ฉ์๊ฐ ๋ค์ํ์ด์ง๋ก ๋์ด๊ฐ๋ ๋ฒํธ๋ฅผ ๋๋ฌ์ค์ผํ๋ค๋ ๋จ์ ์ด ์๋ค.
์ฌ์ฉ์๋ค์ ๋ ๊ธฐ๋ค๋ฆฌ๊ณ , ๋ ํธ๋ฆฌํ๊ฒ ์น์ํ์ ํ๊ณ ์ถ์ดํ๋ค.
์ด๋ฌํ ๋จ์ ์ ๊ทน๋ณตํ๊ธฐ ์ํด ๋์จ ๊ฒ ๋ฌดํ ์คํฌ๋กค(infinite scroll)์ด๋ค.
โ ์์ค ์ฝ๋
์ ์ฒด ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๊ณ ์๋์์ ์ข ๋ ์์ธํ ์ค๋ช ์ ๋๊ณ ์ ํ๋ค.
"use strict";
import { useEffect, useState } from "react";
function App() {
const randomData = [];
const [pageCount, setPageCount] = useState(0);
const [fetching, setFetching] = useState(false); // ์ถ๊ฐ ๋ฐ์ดํฐ๋ฅผ fetchํ๋ ์ค์ธ์ง ์๋์ง ํ์ธํ๋ ์ญํ
const [myData, setMyData] = useState([]); // API๋ก๋ถํฐ ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๊ณณ
const createRandomData = () => {
for (let i = 1; i <= 30; i++) {
const data = {
title: `title ${i}`,
content: Math.random(),
};
randomData.push(data);
}
};
createRandomData();
const handleScroll = () => {
const scrollHeight = document.documentElement.scrollHeight;
const scrollTop = document.documentElement.scrollTop;
const clientHeight = document.documentElement.clientHeight;
// ํ์ด์ง ๋์ ๋๋ฌํ๊ณ fetch๊ฐ ์งํ๋์ง ์๋ ์ํ์ผ ๋ ๋์
if (fetching === false && scrollTop + clientHeight >= scrollHeight) {
fetchMoreData();
}
};
// scroll event listener ๋ฑ๋ก ๋ฐ ํด์
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}]);
const fetchMoreData = async () => {
// ์ถ๊ฐ ๋ฐ์ดํฐ fetchํ๋ ์ํ๋ก ์ ํ
setFetching(true);
if (pageCount >= randomData.length) {
return;
}
const fetchedData = randomData[pageCount];
const mergedData = myData.concat(fetchedData);
setMyData(mergedData);
setPageCount(pageCount + 1);
setFetching(false);
};
return (
<div className="App">
{randomData.map((elem, index) => (
<div key={index}>
<h2>์ผ๋ฐ</h2>
<div>{elem.title}</div>
<div>{elem.content}</div>
</div>
))}
{myData.map((elem, index) => (
<div key={index}>
<h2>์๋ก</h2>
<div>{elem.title}</div>
<div>{elem.content}</div>
</div>
))}
</div>
);
}
export default App;
์ฐ์ ๋ค์๊ณผ ๊ฐ์ด ์ํ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์ด ๋ด๊ธฐ ์ํด randomData๋ฅผ ์ป์ด๋ธ๋ค.
์ด ๊ณผ์ ์ด ์ถํ์๋ api ํธ์ถ์ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋์์ผ๋ก ๋ณ๊ฒฝ๋๋ฉด ๋๊ฒ ๋ค.
const createRandomData = () => {
for (let i = 1; i <= 30; i++) {
const data = {
title: `title ${i}`,
content: Math.random(),
};
randomData.push(data);
}
};
createRandomData();
useEffect๋ฅผ ํตํด scroll ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํด์ค๋ค.
์ด๋ handleScroll์์ ์คํฌ๋กค์ด ๊ฐ์ฅ ํ๋จ์ ๋์ฐฉํ์ ๋ fetchMoreData๋ฅผ ํธ์ถํด์ค๋ค.
๋ํ fetching === false๋ฅผ ํตํด fetch์ค์ ๊ณ์ ์คํฌ๋กค์ ๊ฐ์ฅ ํ๋จ์ผ๋ก ์ฎ๊ฒผ์ ๋ ์ค๋ณตํธ์ถ์ด ๋์ง ์๋๋ก ํ๋ค.
const handleScroll = () => {
const scrollHeight = document.documentElement.scrollHeight;
const scrollTop = document.documentElement.scrollTop;
const clientHeight = document.documentElement.clientHeight;
// ํ์ด์ง ๋์ ๋๋ฌํ๊ณ fetch๊ฐ ์งํ๋์ง ์๋ ์ํ์ผ ๋ ๋์
if (fetching === false && scrollTop + clientHeight >= scrollHeight) {
fetchMoreData();
}
};
// scroll event listener ๋ฑ๋ก ๋ฐ ํด์
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
});
fetchMoreData์์๋ setFetching์ ํตํด ๋ง์น mutex๋ฅผ ์ฐ๋ฏ์ด ์์ ๋๊ธฐํ๋ฅผ ๊ฑธ์ด์ค๋ค.
๊ทธ๋ฆฌ๊ณ setMyData๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด์ค๋ค.
const fetchMoreData = async () => {
// ์ถ๊ฐ ๋ฐ์ดํฐ fetchํ๋ ์ํ๋ก ์ ํ
setFetching(true);
if (pageCount >= randomData.length) {
return;
}
const fetchedData = randomData[pageCount];
const mergedData = myData.concat(fetchedData);
setMyData(mergedData);
setPageCount(pageCount + 1);
setFetching(false);
};
'Basic > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[React] local์์ ์คํ ์ render๊ฐ ๋ ๋ฒ ๋๊ณ ์์ด์! (0) | 2023.01.23 |
---|---|
[React] recoil์ ์ด์ฉํ ์ํ ๊ด๋ฆฌ (0) | 2023.01.20 |
[React] outlet์ ์ด์ฉํ ์ฌ์ด ๋ ์ด์์ ๊ต์ฒด (0) | 2023.01.15 |
[React] Custom hook ๋ชจ์ (0) | 2023.01.02 |
dashboard design example (0) | 2021.03.24 |