Implementing Infinite Scroll in a React Application
Infinite scroll is a common and engaging user interface pattern that dynamically loads content as the user scrolls down a page. This challenge asks you to implement this pattern in a React application using TypeScript, providing a smooth and efficient user experience by fetching and rendering data on demand. This is particularly useful for displaying large datasets like product listings, social media feeds, or news articles.
Problem Description
You are tasked with creating a React component that implements infinite scroll functionality. The component should initially render a small set of data. As the user scrolls towards the bottom of the component, a new chunk of data should be fetched from a simulated API (you don't need to connect to a real API for this challenge) and appended to the existing data. The component should handle loading states and errors gracefully.
Key Requirements:
- Initial Data: The component should render an initial set of data items.
- Data Fetching: A function
fetchDatawill simulate fetching data from an API. This function takes apagenumber as input and returns a Promise that resolves to an array of data items. For simplicity, assumefetchDatareturns a different set of items for each page. - Scroll Listener: The component should listen for scroll events and, when the user scrolls near the bottom of the component, trigger the
fetchDatafunction to load more data. - Loading State: The component should display a loading indicator while data is being fetched.
- Error Handling: The component should display an error message if the data fetching fails.
- Debouncing: Implement debouncing on the scroll event handler to prevent excessive API calls.
- TypeScript: The entire solution must be written in TypeScript.
Expected Behavior:
- The component initially renders with a small set of data (e.g., 10 items).
- As the user scrolls down, when the scroll position is within a certain threshold (e.g., 200px) from the bottom of the component, a loading indicator is displayed.
fetchDatais called with an incremented page number.- Once the data is fetched, the loading indicator is hidden, and the new data is appended to the existing data, updating the UI.
- If
fetchDatafails, an error message is displayed. - The process repeats as the user continues to scroll.
Edge Cases to Consider:
- What happens when there's no more data to fetch? (You don't need to implement a "no more data" message, but consider how the component should behave).
- What happens if the
fetchDatafunction throws an error? - How to handle the initial render and prevent unnecessary API calls before the user starts scrolling?
Examples
Example 1:
Input: Initial data: [“Item 1”, “Item 2”, “Item 3”, “Item 4”, “Item 5”, “Item 6”, “Item 7”, “Item 8”, “Item 9”, “Item 10”]. Scroll to near the bottom.
Output: The component renders the initial 10 items. After scrolling, "Item 11", "Item 12", "Item 13", "Item 14", "Item 15", "Item 16", "Item 17", "Item 18", "Item 19", "Item 20" are appended to the list. A loading indicator is briefly shown during the fetch.
Explanation: The component fetches the next page of data (page 2) and appends it to the existing data.
Example 2:
Input: fetchData throws an error.
Output: An error message is displayed in the component, indicating that the data could not be fetched. The loading indicator is hidden.
Explanation: The component handles the error from fetchData and displays an appropriate message to the user.
Constraints
- The
fetchDatafunction will simulate an API call and should take approximately 500ms to resolve. You can usesetTimeoutto simulate this delay. - The component should be able to handle at least 10 pages of data (each page containing 10 items).
- The debouncing interval for the scroll event handler should be 200ms.
- The scroll threshold for triggering data fetching should be 200px from the bottom of the component.
- The component should be reasonably performant, avoiding unnecessary re-renders.
Notes
- Consider using the
useEffecthook to manage the scroll listener and data fetching. - Use state to manage the data, loading state, and error state.
- Debouncing can be implemented using
setTimeoutor a utility library like Lodash. - Focus on creating a clean and well-structured component that is easy to understand and maintain.
- You can use any styling approach you prefer (CSS, styled-components, etc.). The styling itself is not the focus of this challenge.
- The
fetchDatafunction is provided for you. You only need to implement the component logic. - Assume the data returned by
fetchDatais an array of strings.