Hone logo
Hone
Problems

Smooth Infinite Scrolling with Vue and TypeScript

Implementing smooth, infinite scrolling is a common requirement for modern web applications, especially those displaying large datasets. This challenge asks you to create a Vue component that dynamically loads and displays content as the user scrolls near the bottom of the container, providing a seamless and engaging user experience. This is useful for displaying long lists of items, articles, or any other content that would be impractical to load all at once.

Problem Description

You need to build a Vue component called InfiniteScroll that handles the loading and display of data in a scrollable container. The component should:

  1. Accept a data source: The component should receive a data prop, which is an array of data items to display.
  2. Load more data: When the user scrolls near the bottom of the container (within a specified threshold), the component should trigger a loadMore event. This event should be emitted by the parent component, allowing it to fetch the next batch of data.
  3. Display data: The component should render the received data items within a scrollable container.
  4. Loading State: Display a loading indicator while waiting for more data to be fetched.
  5. Error Handling: Display an error message if the loadMore event fails to produce data after a reasonable timeout.

Key Requirements:

  • Use the IntersectionObserver API to detect when the user is near the bottom of the container.
  • Implement a loading indicator to provide visual feedback to the user.
  • Handle potential errors during data loading.
  • The component should be reusable and configurable.

Expected Behavior:

  • The component should initially render the provided data.
  • As the user scrolls, an IntersectionObserver should monitor a sentinel element (created by the component) placed at the bottom of the container.
  • When the sentinel element is near the bottom of the viewport (within a configurable threshold), the loadMore event should be emitted.
  • The loading indicator should be displayed while waiting for the loadMore event to resolve.
  • If the loadMore event does not resolve within a specified timeout, an error message should be displayed.
  • Once new data is received (via the loadMore event), the component should append the new data to the existing data and re-render.

Edge Cases to Consider:

  • What happens if the loadMore event never emits data? (Implement a timeout and error handling)
  • What happens if the data source is empty? (Handle the initial render gracefully)
  • What happens if the user scrolls back up after triggering loadMore? (Avoid redundant requests)
  • Consider different screen sizes and scroll behaviors.

Examples

Example 1:

Input: data = [{id: 1, name: 'Item 1'}, {id: 2, name: 'Item 2'}] , threshold = 200, timeout = 1000
Output: A Vue component displaying "Item 1" and "Item 2" in a scrollable container. As the user scrolls near the bottom (within 200px), a loading indicator is shown, and the parent component is expected to emit more data. If no data is received within 1 second, an error message is displayed.
Explanation: The component initializes with the provided data and sets up an IntersectionObserver to detect when the user is near the bottom of the container.

Example 2:

Input: data = [], threshold = 100, timeout = 500
Output: An empty scrollable container with a loading indicator initially. No data is displayed until the parent component emits data via the loadMore event.
Explanation: The component handles the case where the initial data array is empty.

Example 3: (Edge Case)

Input: data = [{id: 1, name: 'Item 1'}], threshold = 50, timeout = 2000, loadMore event never emits data.
Output: The component initially displays "Item 1". After scrolling near the bottom and waiting for 2 seconds, an error message "Failed to load more data" is displayed.
Explanation: The component demonstrates error handling when the loadMore event fails to resolve within the timeout.

Constraints

  • The component should be written in TypeScript.
  • The data prop should be an array of any type.
  • threshold prop should be a number representing the distance from the bottom of the container to trigger loadMore (in pixels). Must be between 1 and 500.
  • timeout prop should be a number representing the timeout (in milliseconds) for the loadMore event. Must be between 500 and 5000.
  • The component should be performant and avoid unnecessary re-renders.
  • The component should be compatible with modern browsers.

Notes

  • Consider using a reactive variable to store the data and trigger re-renders when new data is received.
  • The loadMore event should be emitted with a payload (e.g., a cursor or page number) to help the parent component fetch the next batch of data.
  • The sentinel element can be a simple div with a specific height.
  • Think about how to handle the case where the user scrolls back up after triggering loadMore. You might want to debounce the loadMore event to avoid redundant requests.
  • Focus on clean, readable, and maintainable code. Properly document your code.
Loading editor...
typescript