Hone logo
Hone
Problems

Advanced Vue Component Optimization with Virtual Scrolling and Debouncing

This challenge focuses on building a highly performant Vue 3 component that displays a large list of items. You will implement two key optimization techniques: virtual scrolling to efficiently render only visible items and debouncing for handling user input that filters this list. This is crucial for applications dealing with extensive datasets, ensuring a smooth and responsive user experience.

Problem Description

Your task is to create a Vue 3 component named OptimizedListComponent that renders a potentially very large array of Item objects. The component should dynamically load and unload items based on the user's scroll position, a technique known as virtual scrolling. Additionally, it should provide an input field to filter the displayed items based on a name property, with the filtering logic debounced to prevent excessive computations on rapid typing.

Key Requirements:

  1. Virtual Scrolling:
    • The component must render only the items currently visible within the viewport, plus a small buffer.
    • As the user scrolls, items outside the viewport (and buffer) should be removed from the DOM, and new items should be added.
    • The scrollable container should have a fixed height.
    • Each Item object has a fixed height.
  2. Filtering:
    • An input field should be present to filter the items array.
    • The filter should be based on a case-insensitive match of the name property of each Item.
    • The filtering logic should be debounced with a delay of 300ms. This means the filter function will only execute after the user has stopped typing for 300ms.
  3. State Management:
    • The component should manage its own internal state for the list of items, the filter text, and the currently visible items.

Expected Behavior:

  • When a large list of items is passed to the component, only a subset should be rendered in the DOM initially.
  • Scrolling down the list should progressively render new items and remove old ones, maintaining a smooth scroll.
  • Typing into the filter input should trigger filtering. The list should update only after a brief pause in typing.
  • The component should correctly handle scrolling to the top and bottom of the list.
  • If the filtered list becomes empty, a "No results found" message should be displayed.

Edge Cases:

  • An empty initial items array.
  • A filter string that matches no items.
  • Very rapid typing in the filter input.
  • Scrolling very quickly through a large list.
  • The items array being smaller than the visible area.

Examples

Let's define our Item interface:

interface Item {
  id: number;
  name: string;
  // ... other potential properties
}

Example 1: Initial Load and Scrolling

Input:

const items: Item[] = Array.from({ length: 1000 }, (_, i) => ({
  id: i,
  name: `Item ${i}`,
}));
const itemHeight = 50; // px
const containerHeight = 400; // px

Output:

The DOM will initially render approximately containerHeight / itemHeight (e.g., 8 items) plus a buffer. As the user scrolls, the rendered items will update to reflect the visible portion of the items array.

Explanation: The component efficiently renders only the items that are currently visible, preventing performance degradation with large datasets.

Example 2: Filtering

Input:

const items: Item[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
  { id: 3, name: "Orange" },
  { id: 4, name: "Pineapple" },
  { id: 5, name: "Grape" },
];
const itemHeight = 50;
const containerHeight = 200;

User input in the filter field: "app"

Output:

The component will display:

  • Apple
  • Pineapple

Explanation: The filtering is case-insensitive and matches substrings. The debouncing ensures that the filtering operation is not performed on every keystroke but rather after a short pause, improving performance.

Example 3: Empty Filter Results

Input:

const items: Item[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
];
const itemHeight = 50;
const containerHeight = 200;

User input in the filter field: "xyz"

Output:

A message "No results found" is displayed.

Explanation: When the filter criteria result in an empty dataset, a user-friendly message is shown instead of a blank list.

Constraints

  • The items array can contain up to 100,000 elements.
  • Each Item object has a fixed height (provided as a prop to the component).
  • The scrollable containerHeight is fixed (provided as a prop).
  • The debounce delay for filtering is 300ms.
  • The solution must be implemented using Vue 3 Composition API and TypeScript.
  • Performance is critical; the component should remain responsive even with the maximum number of items.

Notes

  • Consider how to calculate the number of items to render based on containerHeight and itemHeight.
  • A buffer around the visible items can significantly improve the perceived smoothness of scrolling. A common approach is to render N items above and N items below the currently visible items.
  • For debouncing, you can use a utility function or implement it manually within the component's script setup.
  • Think about how to position the list of rendered items correctly using CSS transform or padding to simulate the full height of the original list.
  • The id property of Item can be used as a unique key for Vue's list rendering.
  • Ensure the filter comparison is case-insensitive.
Loading editor...
typescript