๐ฐ 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 |