React Table with Server-Side Pagination
This challenge requires you to build a robust and user-friendly table component in React that supports server-side pagination. Implementing pagination is a fundamental skill for handling large datasets efficiently, improving user experience by breaking down information into manageable chunks.
Problem Description
Your task is to create a reusable React component named PaginatedTable that displays data in a table format with client-side controls for pagination. The component should fetch data from a simulated API and manage the display of data based on the current page, items per page, and total number of items.
Key Requirements:
- Data Fetching: The component should simulate fetching data from an API. For this challenge, you can use a predefined array of data and a mock
fetchDatafunction. - Pagination State Management: You need to manage the following state within the component:
currentPage: The currently displayed page number (starts at 1).itemsPerPage: The number of items to display per page (e.g., 10).totalItems: The total number of items available from the API.data: The subset of data to be displayed on the current page.loading: A boolean to indicate if data is being fetched.
- Table Display: Render the fetched
datain a clear, well-formatted HTML table. The table should have columns relevant to the data (e.g., Name, Email, Role). - Pagination Controls: Implement UI controls to allow users to navigate through pages:
- "Previous" button: Enabled only if
currentPage > 1. - "Next" button: Enabled only if
currentPage < Math.ceil(totalItems / itemsPerPage). - Page number display: Show the current page and total pages (e.g., "Page 1 of 10").
- "Previous" button: Enabled only if
- Item Count Display: Display the range of items currently shown (e.g., "Showing 1-10 of 100 items").
- Data Update on Page Change: When the user clicks "Previous" or "Next," update the
currentPagestate and re-fetch/re-calculate thedatafor the new page. - Loading Indicator: While data is being fetched (simulated by a
setTimeout), display a "Loading..." message or a spinner.
Expected Behavior:
- On initial render, the table displays the first page of data.
- Users can click "Previous" and "Next" to navigate between pages.
- The pagination controls update dynamically based on the current page and total items.
- A loading indicator is shown during data fetching.
Edge Cases:
- Empty Data: What happens if the API returns an empty array?
- Single Page: If
totalItemsis less than or equal toitemsPerPage, only one page should be displayed, and navigation buttons might be disabled. - Last Page with Fewer Items: The "Showing X-Y of Z items" should correctly reflect the number of items on the last page if it's not full.
Examples
Example 1: Initial Load
Input Data (simulated API response):
{
items: [
{ id: 1, name: 'Alice Smith', email: 'alice@example.com', role: 'Admin' },
{ id: 2, name: 'Bob Johnson', email: 'bob@example.com', role: 'Editor' },
{ id: 3, name: 'Charlie Brown', email: 'charlie@example.com', role: 'Viewer' },
{ id: 4, name: 'Diana Prince', email: 'diana@example.com', role: 'Admin' },
{ id: 5, name: 'Ethan Hunt', email: 'ethan@example.com', role: 'Editor' },
{ id: 6, name: 'Fiona Glenn', email: 'fiona@example.com', role: 'Viewer' },
{ id: 7, name: 'George Jetson', email: 'george@example.com', role: 'Admin' },
{ id: 8, name: 'Hannah Montana', email: 'hannah@example.com', role: 'Editor' },
{ id: 9, name: 'Ian Malcolm', email: 'ian@example.com', role: 'Viewer' },
{ id: 10, name: 'Jane Doe', email: 'jane@example.com', role: 'Admin' },
{ id: 11, name: 'Kevin McCallister', email: 'kevin@example.com', role: 'Editor' },
{ id: 12, name: 'Leia Organa', email: 'leia@example.com', role: 'Viewer' },
{ id: 13, name: 'Michael Scott', email: 'michael@example.com', role: 'Admin' },
{ id: 14, name: 'Nancy Drew', email: 'nancy@example.com', role: 'Editor' },
{ id: 15, name: 'Oliver Twist', email: 'oliver@example.com', role: 'Viewer' }
],
totalItems: 15
}
Items per page: 5
Output (Rendered Table and Controls):
| Name | Email | Role |
|----------------|-------------------|--------|
| Alice Smith | alice@example.com | Admin |
| Bob Johnson | bob@example.com | Editor |
| Charlie Brown | charlie@example.com | Viewer |
| Diana Prince | diana@example.com | Admin |
| Ethan Hunt | ethan@example.com | Editor |
Showing 1-5 of 15 items
Page 1 of 3
[< Previous] [Next >]
Example 2: Navigating to Next Page
Scenario: User clicks "Next" on Example 1.
Current Page: 1
Items per page: 5
Total Items: 15
Output (Rendered Table and Controls):
| Name | Email | Role |
|----------------|---------------------|--------|
| Fiona Glenn | fiona@example.com | Viewer |
| George Jetson | george@example.com | Admin |
| Hannah Montana | hannah@example.com | Editor |
| Ian Malcolm | ian@example.com | Viewer |
| Jane Doe | jane@example.com | Admin |
Showing 6-10 of 15 items
Page 2 of 3
[< Previous] [Next >]
Example 3: Last Page
Scenario: User clicks "Next" on Example 2.
Current Page: 2
Items per page: 5
Total Items: 15
Output (Rendered Table and Controls):
| Name | Email | Role |
|-------------------|-----------------------|--------|
| Kevin McCallister | kevin@example.com | Editor |
| Leia Organa | leia@example.com | Viewer |
| Michael Scott | michael@example.com | Admin |
| Nancy Drew | nancy@example.com | Editor |
| Oliver Twist | oliver@example.com | Viewer |
Showing 11-15 of 15 items
Page 3 of 3
[< Previous] [Next >]
Constraints
- The
PaginatedTablecomponent should acceptdata(an array of objects) andtotalItemsas props. - The component should also accept an optional
itemsPerPageprop, with a default value of 10. - The
fetchDatafunction should simulate an asynchronous operation usingsetTimeout(e.g., 500ms). - The data objects will have at least
id,name,email, androleproperties. - The solution must be implemented in TypeScript.
- The component should be functional and use React Hooks.
Notes
- You are free to choose your preferred styling approach (e.g., CSS Modules, styled-components, or inline styles). Focus on functionality first.
- Consider how you would handle errors if the API fetch failed in a real-world scenario (though error handling is not a primary focus of this challenge).
- The "Previous" and "Next" buttons should be disabled appropriately.
- The
idproperty of each data item is guaranteed to be unique and can be used as thekeyprop for table rows.