React Virtualized List Component
Creating a virtualized list component is crucial for efficiently rendering large datasets in React applications. Traditional rendering can lead to performance bottlenecks when dealing with thousands or millions of items, as all items are rendered and kept in the DOM. This challenge asks you to build a basic virtualized list that only renders items within the visible viewport, significantly improving performance.
Problem Description
You are tasked with building a simple virtualized list component in React using TypeScript. The component should accept an array of data items and render them as a list. The key requirement is that only a subset of the items, those currently visible within the viewport, should be rendered to the DOM. As the user scrolls, the component should dynamically update the rendered items to reflect the visible portion of the data.
Key Requirements:
- Data Input: The component should accept a
dataprop, which is an array of any typeT. - Item Rendering: The component should accept an
itemRendererprop, a function that takes a single item of typeTand returns a React element to render for that item. - Viewport Calculation: The component should calculate the start and end indices of the items that are currently visible within the viewport.
- Dynamic Rendering: Only the items within the calculated viewport indices should be rendered to the DOM.
- Scrolling: The component should handle scrolling events and update the viewport calculation and rendered items accordingly.
- List Size: The component should display the total number of items in the data array.
Expected Behavior:
- When the component mounts, it should render the initial set of items visible in the viewport (assuming a default viewport height).
- As the user scrolls, the component should dynamically update the rendered items to match the visible portion of the data.
- The
itemRendererfunction should be called for each rendered item, allowing for custom rendering logic. - The component should handle cases where the data array is empty.
- The component should handle cases where the viewport is smaller than the total number of items.
Edge Cases to Consider:
- Empty data array.
- Viewport height is zero or negative.
- Data array contains items of varying heights (though this challenge focuses on uniform height for simplicity).
- Scrolling beyond the bounds of the data array (though this is not a primary requirement, consider how it might be handled).
Examples
Example 1:
Input: data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], itemRenderer = (item) => <div>{item}</div>, viewportHeight = 200
Output: A list displaying items 1, 2, 3, 4, 5 (assuming each item takes up 20px of height, and the viewport can fit 10 items). Scrolling down should render items 6, 7, 8.
Explanation: The component calculates the visible items based on the viewport height and renders only those.
Example 2:
Input: data = [], itemRenderer = (item) => <div>{item}</div>, viewportHeight = 200
Output: An empty list.
Explanation: The component handles the case where the data array is empty.
Example 3:
Input: data = [1, 2], itemRenderer = (item) => <div>{item}</div>, viewportHeight = 500
Output: A list displaying items 1 and 2.
Explanation: The component renders all items since the viewport is larger than the data array.
Constraints
- Performance: The component should be performant, minimizing unnecessary re-renders. Avoid re-rendering items that are not visible.
- Data Size: The
dataarray can contain up to 1000 items. - Item Height: For simplicity, assume all items have a uniform height of 30px. This can be adjusted via a prop in a future iteration.
- Viewport Height: The
viewportHeightprop should be a positive number representing the height of the visible area in pixels. - TypeScript: The solution must be written in TypeScript.
Notes
- Consider using React's
useRefhook to manage the scroll position. - The
itemRendererfunction provides flexibility in how each item is rendered. - Focus on the core virtualization logic – you don't need to implement complex features like drag-and-drop or sorting.
- Think about how to efficiently calculate the visible item indices based on the scroll position and item height.
- A simple approach is to use a
useEffecthook to listen for scroll events and update the rendered items accordingly. However, be mindful of performance implications within theuseEffect.