Front-end/React

[React] React-Virtualized: ์—„์ฒญ๋‚œ ์–‘์˜ ๋ฐ์ดํ„ฐ๋„ ๊ฐ€๋ณ๊ฒŒ ๋ Œ๋”๋งํ•˜๊ธฐ! ๐Ÿš€

xeunnie 2024. 12. 23. 01:00
728x90
๋ฐ˜์‘ํ˜•

React-Virtualized ํ†บ์•„๋ณด๊ธฐ! ๐Ÿš€

๋ฆฌ์•กํŠธ๋กœ ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ…Œ์ด๋ธ”, ๋ฆฌ์ŠคํŠธ, ๋˜๋Š” ๊ทธ๋ฆฌ๋“œ ํ˜•ํƒœ๋กœ ๋ Œ๋”๋งํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ํ™”๋ฉด์— ๋ณด์ด์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์ „๋ถ€ ๋ Œ๋”๋งํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋А๋ ค์ง€๊ณ , ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์ฃ . ์—ฌ๊ธฐ์„œ ๋“ฑ์žฅํ•˜๋Š” ํ•ด๊ฒฐ์‚ฌ๊ฐ€ ๋ฐ”๋กœ React-Virtualized์ž…๋‹ˆ๋‹ค!


React-Virtualized๋ž€? ๐Ÿš

React-Virtualized๋Š” ๊ธด ๋ฆฌ์ŠคํŠธ๋‚˜ ํ…Œ์ด๋ธ”์„ ํšจ์œจ์ ์œผ๋กœ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ๋ณด์ด๋Š” ์˜์—ญ(viewport)์— ํ•ด๋‹นํ•˜๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋ Œ๋”๋งํ•˜๊ณ , ์Šคํฌ๋กค์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์•„์ดํ…œ์„ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ‘‰ ๊ฐ€์ƒํ™”(Virtualization): ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ‘๋ณด์ด๋Š” ๋งŒํผ’ ๊ทธ๋ ค์คŒ์œผ๋กœ์จ DOM์„ ๊ฐ€๋ณ๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค.


์™œ React-Virtualized๋ฅผ ์จ์•ผ ํ• ๊นŒ?

1. ์„ฑ๋Šฅ ์ตœ์ ํ™”

๋ธŒ๋ผ์šฐ์ €๋Š” ์ˆ˜์ฒœ ๊ฐœ์˜ DOM ์š”์†Œ๋ฅผ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์›Œ์š”. React-Virtualized๋Š” ํ•„์š”ํ•œ DOM๋งŒ ์ƒ์„ฑํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ค„์ด๊ณ , ๋ Œ๋”๋ง ์†๋„๋ฅผ ๋†’์ž…๋‹ˆ๋‹ค.

 

2. ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ ์ œ๊ณต

๋ฆฌ์ŠคํŠธ, ๊ทธ๋ฆฌ๋“œ, ํ…Œ์ด๋ธ” ๊ฐ™์€ UI ์š”์†Œ๋ฅผ ์ตœ์ ํ™”๋œ ๋ฐฉ์‹์œผ๋กœ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

3. ๊ฐ„ํŽธํ•œ ์‚ฌ์šฉ๋ฒ•

์‰ฝ๊ฒŒ ์„ค์น˜ํ•˜๊ณ  ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.


์ฃผ์š” ์ปดํฌ๋„ŒํŠธ

React-Virtualized๋Š” ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ, ํ•ต์‹ฌ ์ปดํฌ๋„ŒํŠธ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

1. List

์Šคํฌ๋กค ๊ฐ€๋Šฅํ•œ ๊ธด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

2. Grid

ํ–‰(row)๊ณผ ์—ด(column)๋กœ ๊ตฌ์„ฑ๋œ ๋ฐ์ดํ„ฐ(์˜ˆ: ๋Œ€๊ทœ๋ชจ ํ…Œ์ด๋ธ”)๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

3. AutoSizer

ํ™”๋ฉด ํฌ๊ธฐ์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ ํฌ๊ธฐ๋ฅผ ๋™์ ์œผ๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

 

4. InfiniteLoader

๋ฌดํ•œ ์Šคํฌ๋กค ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


์„ค์น˜ํ•˜๊ธฐ

๋จผ์ € ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์•ผ๊ฒ ์ฃ ?

npm install react-virtualized
# ๋˜๋Š”
yarn add react-virtualized

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

๋ฆฌ์ŠคํŠธ(List) ์ปดํฌ๋„ŒํŠธ

๊ธด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

import React from "react";
import { List } from "react-virtualized";

const rowCount = 1000; // 1,000๊ฐœ์˜ ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ
const rowHeight = 50; // ๊ฐ ์•„์ดํ…œ์˜ ๋†’์ด

const rowRenderer = ({ key, index, style }) => (
  <div key={key} style={style}>
    Row #{index}
  </div>
);

function App() {
  return (
    <List
      width={300} // ๋ฆฌ์ŠคํŠธ ๋„ˆ๋น„
      height={300} // ๋ฆฌ์ŠคํŠธ ๋†’์ด
      rowHeight={rowHeight} // ๊ฐ ์•„์ดํ…œ์˜ ๋†’์ด
      rowCount={rowCount} // ์ด ์•„์ดํ…œ ๊ฐœ์ˆ˜
      rowRenderer={rowRenderer} // ๊ฐ ์•„์ดํ…œ ๋ Œ๋”๋ง ๋ฐฉ์‹
    />
  );
}

export default App;

๊ทธ๋ฆฌ๋“œ(Grid) ์ปดํฌ๋„ŒํŠธ

ํ…Œ์ด๋ธ” ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

import React from "react";
import { Grid } from "react-virtualized";

const cellRenderer = ({ columnIndex, key, rowIndex, style }) => (
  <div key={key} style={style}>
    Cell {rowIndex}, {columnIndex}
  </div>
);

function App() {
  return (
    <Grid
      cellRenderer={cellRenderer} // ์…€ ๋ Œ๋”๋ง ๋ฐฉ์‹
      columnCount={10} // ์—ด์˜ ๊ฐœ์ˆ˜
      columnWidth={100} // ๊ฐ ์—ด์˜ ๋„ˆ๋น„
      height={300} // ๊ทธ๋ฆฌ๋“œ ๋†’์ด
      rowCount={10} // ํ–‰์˜ ๊ฐœ์ˆ˜
      rowHeight={50} // ๊ฐ ํ–‰์˜ ๋†’์ด
      width={800} // ๊ทธ๋ฆฌ๋“œ ๋„ˆ๋น„
    />
  );
}

export default App;

AutoSizer์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ

ํ™”๋ฉด ํฌ๊ธฐ์— ๋งž๊ฒŒ ๋ฆฌ์ŠคํŠธ ๋˜๋Š” ๊ทธ๋ฆฌ๋“œ์˜ ํฌ๊ธฐ๋ฅผ ์ž๋™์œผ๋กœ ์กฐ์ •ํ•˜๋ ค๋ฉด AutoSizer๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

import React from "react";
import { List, AutoSizer } from "react-virtualized";

const rowRenderer = ({ key, index, style }) => (
  <div key={key} style={style}>
    Row #{index}
  </div>
);

function App() {
  return (
    <AutoSizer>
      {({ width, height }) => (
        <List
          width={width}
          height={height}
          rowHeight={50}
          rowCount={1000}
          rowRenderer={rowRenderer}
        />
      )}
    </AutoSizer>
  );
}

export default App;

InfiniteLoader๋กœ ๋ฌดํ•œ ์Šคํฌ๋กค ๊ตฌํ˜„ํ•˜๊ธฐ

๋ฌดํ•œ ์Šคํฌ๋กค์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด InfiniteLoader๋ฅผ ํ™œ์šฉํ•˜์„ธ์š”.

import React, { useState } from "react";
import { List, InfiniteLoader } from "react-virtualized";

const rowCount = 1000;
const loadMoreRows = ({ startIndex, stopIndex }) =>
  new Promise((resolve) => {
    console.log(`Loading rows ${startIndex} to ${stopIndex}`);
    setTimeout(resolve, 1000); // API ํ˜ธ์ถœ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
  });

const rowRenderer = ({ key, index, style }) => (
  <div key={key} style={style}>
    Row #{index}
  </div>
);

function App() {
  const [loadedRowsMap, setLoadedRowsMap] = useState({});
  const isRowLoaded = ({ index }) => !!loadedRowsMap[index];

  return (
    <InfiniteLoader
      isRowLoaded={isRowLoaded}
      loadMoreRows={loadMoreRows}
      rowCount={rowCount}
    >
      {({ onRowsRendered, registerChild }) => (
        <List
          width={300}
          height={300}
          rowHeight={50}
          rowCount={rowCount}
          onRowsRendered={onRowsRendered}
          ref={registerChild}
          rowRenderer={rowRenderer}
        />
      )}
    </InfiniteLoader>
  );
}

export default App;

React-Virtualized์˜ ์žฅ์ 

  1. ํผํฌ๋จผ์Šค: ์ˆ˜์ฒœ ~ ์ˆ˜๋ฐฑ๋งŒ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ๋„ ๋ Œ๋”๋ง์ด ๋น ๋ฆ…๋‹ˆ๋‹ค.
  2. ์œ ์—ฐ์„ฑ: ๋ฆฌ์ŠคํŠธ, ํ…Œ์ด๋ธ”, ๊ทธ๋ฆฌ๋“œ ๋“ฑ ๋‹ค์–‘ํ•œ UI๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ: ๊ฐ€์ƒํ™”๋กœ ๋ถˆํ•„์š”ํ•œ DOM ์ƒ์„ฑ ๋ฐฉ์ง€.

์ฃผ์˜์‚ฌํ•ญ

  1. ์Šคํƒ€์ผ ์ง€์ •: ๊ฐ ํ•ญ๋ชฉ์€ style ์†์„ฑ์„ ํ†ตํ•ด ์œ„์น˜์™€ ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ Œ๋”๋ง ๋น„์šฉ: rowRenderer์™€ ๊ฐ™์€ ๋ Œ๋”๋ง ํ•จ์ˆ˜๋Š” ๊ฐ€๋ฒผ์šด ์—ฐ์‚ฐ๋งŒ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€์˜ ๋น„๊ต: react-window๋Š” React-Virtualized์˜ ๊ฐ€๋ฒผ์šด ๋Œ€์•ˆ์œผ๋กœ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

React-Virtualized๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ์–‘์ด ๋งŽ์•„๋„ ์„ฑ๋Šฅ ์ข‹์€ ๋ฆฌ์ŠคํŠธ๋‚˜ ํ…Œ์ด๋ธ”์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ฒ˜์Œ์—” ์•ฝ๊ฐ„ ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•œ ๋ฒˆ ์ตํžˆ๋ฉด ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

 

๐ŸŒท์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ด…์‹œ๋‹น! ๐ŸŒท

728x90
๋ฐ˜์‘ํ˜•