Hone logo
Hone
Problems

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:

  1. 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 fetchData function.
  2. 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.
  3. Table Display: Render the fetched data in a clear, well-formatted HTML table. The table should have columns relevant to the data (e.g., Name, Email, Role).
  4. 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").
  5. Item Count Display: Display the range of items currently shown (e.g., "Showing 1-10 of 100 items").
  6. Data Update on Page Change: When the user clicks "Previous" or "Next," update the currentPage state and re-fetch/re-calculate the data for the new page.
  7. 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 totalItems is less than or equal to itemsPerPage, 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 PaginatedTable component should accept data (an array of objects) and totalItems as props.
  • The component should also accept an optional itemsPerPage prop, with a default value of 10.
  • The fetchData function should simulate an asynchronous operation using setTimeout (e.g., 500ms).
  • The data objects will have at least id, name, email, and role properties.
  • 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 id property of each data item is guaranteed to be unique and can be used as the key prop for table rows.
Loading editor...
typescript