React|Optimization & Security

Rendering Massive Data: Maintaining DOM Node Count with Virtualization (React Window)

0
Rendering Massive Data: Maintaining DOM Node Count with Virtualization (React Window)

Chris is building an admin dashboard. His current mission is to display a list of 'All 10,000 User Logs'.

Without thinking much, he rendered 10,000 divs using the map function.

// ❌ Code that kills the browser
{logs.map(log => <LogItem key={log.id} data={log} />)}

The moment he refreshed the page, the browser froze. Scrolling stuttered, and mouse clicks became unresponsive.

No matter how fast React is, creating and managing 10,000 DOM nodes at once is too much. The area the browser has to calculate positions for (Reflow) and color in (Repaint) is simply too vast.

To solve this problem, we need to use a technique called Virtualization, or Windowing.

1. The Principle of Windowing

The principle is simple: "Draw only what is visible."

Even if there are 10,000 data items, only about 10 to 20 fit inside the user's monitor screen (Viewport).

  • We simply do not render the remaining 9,980 items. (They do not exist in the DOM).
  • Instead, we insert a massive amount of Padding (empty space) above and below to maintain the correct scrollbar size.
  • When the user scrolls, we swap the content with the items corresponding to that position.
  • As a result, there are always only around 20 nodes existing in the DOM. Whether the data is 100,000 or 1 million items, the browser remains smooth and responsive.

    2. Choosing a Library: react-window

    There is no need to implement this complex scroll calculation logic yourself. You can use react-window, a battle-tested library created by a React core team member. (It is much lighter and faster than the older react-virtualized.)

    Basic Usage (FixedSizeList)

    If the height of the items is fixed, use FixedSizeList.

    // LogList.tsx
    import { FixedSizeList as List } from 'react-window';
    
    // 1. Component to render each Row
    // You MUST accept 'style' as a prop and apply it for positioning to work.
    const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => (
      <div style={style} className="log-item">
        Log #{index} - {logs[index].message}
      </div>
    );
    
    function LogList() {
      return (
        <List
          height={500}        // Total height of the list (px)
          itemCount={10000}   // Total number of items
          itemSize={50}       // Height per item (px)
          width={300}         // Total width of the list (px)
        >
          {Row}
        </List>
      );
    }

    Now, even with 10,000 logs, the DOM contains only enough elements to fill the screen size.

    3. Handling Responsive Width (AutoSizer)

    react-window requires fixed numerical pixel values for width and height.

    But we are building a responsive web app. What if the list needs to stretch to fill the screen (100%)?

    In this case, you need to use a separate package called react-virtualized-auto-sizer. It measures the size of the parent container and passes the width and height down.

    // ResponsiveLogList.tsx
    import AutoSizer from 'react-virtualized-auto-sizer';
    import { FixedSizeList as List } from 'react-window';
    
    function ResponsiveLogList() {
      return (
        <div style={{ flex: 1, height: '100vh' }}>
          <AutoSizer>
            {({ height, width }) => (
              <List
                height={height} // Received parent height
                width={width}   // Received parent width
                itemCount={10000}
                itemSize={50}
              >
                {Row}
              </List>
            )}
          </AutoSizer>
        </div>
      );
    }

    4. Caveats and Limitations

    Virtualization is not a silver bullet. There are a few constraints.

    1. Height Calculation Issues (VariableSizeList)

    What if items have different heights, like chat messages? You have to pass a function instead of a number to itemSize to calculate it. However, if heights are unpredictable due to text wrapping, the implementation difficulty skyrockets.

    2. Search (Ctrl+F) Issues

    The browser's native find function (Ctrl+F) can only find text that exists in the DOM. In a virtualized list, text off-screen does not exist in the DOM, so it cannot be searched. You must implement a separate search feature.

    3. Accessibility and SEO

    Screen readers and search engine bots might only see an empty shell. If SEO is critical for the page, apply virtualization with caution.

    Key Takeaways

  • Problem: Rendering massive amounts of data creates too many DOM nodes, drastically degrading browser performance.
  • Solution: Use react-window to render only the visible parts (Virtualization).
  • Implementation: FixedSizeList is the standard, and AutoSizer is used for responsive layouts.
  • Constraints: Native browser search (Ctrl+F) doesn't work, and dynamic height calculation is tricky.

  • We have covered performance optimization techniques. Now, let's move on to the Security domain to keep our app safe.

    When implementing login, where should we store the token? Local Storage? Cookies?

    It's time to learn the dance of Access Tokens and Refresh Tokens.

    Part 4 continues with the third topic: “Access Token and Refresh Token: Safe Authentication Strategy between Security and UX”

    🔗 References

  • react-window GitHub
  • react-virtualized-auto-sizer
  • Comments (0)

    0/1000 characters
    Loading comments...