As React applications evolve and begin consuming real APIs, displaying all records at once becomes inefficient and difficult to manage. Enterprise applications such as CRM systems, SharePoint portals, ticket management systems, employee directories, administrative dashboards, and reporting platforms commonly use pagination to divide large datasets into smaller and more manageable groups.

App 66 — Pagination System with React, TypeScript, Fluent UI, and Vite

Introduction

As React applications evolve and begin consuming real APIs, displaying all records at once becomes inefficient and difficult to manage. Enterprise applications such as CRM systems, SharePoint portals, ticket management systems, employee directories, administrative dashboards, and reporting platforms commonly use pagination to divide large datasets into smaller and more manageable groups.

In App 66 — Pagination System, we continue our journey through Block 4 — Effects and Architecture, focusing on one of the most important enterprise UI patterns: data paging.

This application demonstrates how React state controls navigation through datasets, how APIs are consumed correctly using useEffect, and how Fluent UI can be used to create a professional Microsoft-style interface.

According to the ReactLab roadmap, App 66 introduces:

  • API consumption
  • Pagination logic
  • Derived state
  • Loading states
  • Enterprise data navigation
  • Component composition
  • Service layer architecture

The React mental model remains unchanged:

State changes
→ React re-renders
→ UI updates automatically

The difference is that now state controls not only data but also which portion of that data is visible.


Learning Objectives

By completing this application, you will learn:

  • How to fetch remote data
  • How to store records using React state
  • How to create page navigation controls
  • How to calculate derived values
  • How to display loading indicators
  • How to organize API access into services
  • How to separate responsibilities between components

Creating the Project

Create the Application

mkdir bloco04
cd bloco04
npm create vite@latest app66-pagination-system -- --template react-ts
cd app66-pagination-system
npm install
npm install @fluentui/react-components

Create the Folder Structure

mkdir src\components
mkdir src\models
mkdir src\services
mkdir src\data
mkdir src\styles

Create the Files

New-Item src\models\User.ts -ItemType File
New-Item src\services\UserService.ts -ItemType File
New-Item src\components\UserTable.tsx -ItemType File
New-Item src\components\PaginationBar.tsx -ItemType File
New-Item src\main.tsx -ItemType File
New-Item src\index.css -ItemType File
New-Item artigo.md -ItemType File

Final Folder Structure

src/
├── components/
│ ├── PaginationBar.tsx
│ └── UserTable.tsx
├── models/
│ └── User.ts
├── services/
│ └── UserService.ts
├── styles/
├── App.tsx
├── main.tsx
└── index.css

This structure separates:

  • Data contracts
  • API communication
  • Presentation components
  • Application orchestration

This separation becomes essential in enterprise React applications.


Understanding the User Model

User.ts

export interface User {
id: number;
name: string;
email: string;
phone: string;
}

This interface defines the structure of every user returned by the API.

TypeScript provides:

  • IntelliSense
  • Type safety
  • Compile-time validation
  • Safer refactoring

Instead of guessing the shape of the data, React knows exactly what fields exist.


Understanding the Service Layer

UserService.ts

import type { User } from "../models/User";
export async function getUsers(): Promise<User[]> {
const response = await fetch(
"https://jsonplaceholder.typicode.com/users"
);
return await response.json();
}

The service layer isolates API logic.

Benefits:

  • Cleaner UI components
  • Easier maintenance
  • Easier testing
  • Reusable data access

Enterprise applications often contain dozens of services, making this pattern extremely important.


Understanding React Effects

The API is loaded using:

useEffect(() => {
async function loadData() {
const result = await getUsers();
setUsers(result);
setLoading(false);
}
loadData();
}, []);

According to React Learn:

Effects synchronize components with external systems.

An API is an external system.

Therefore:

API call
→ useEffect

is the correct React pattern.


Understanding Pagination State

The current page is stored using:

const [page, setPage] = useState(1);

React remembers the page number between renders.

When the user clicks:

Next

React updates state:

setPage(page + 1);

React then re-renders automatically.

No manual DOM updates are required.


Calculating the Current Records

The page size is:

const PAGE_SIZE = 3;

The first record index is:

const start =
(page - 1) * PAGE_SIZE;

Example:

PageStart Index
10
23
36
49

The visible records are:

const currentUsers =
users.slice(start, start + PAGE_SIZE);

This creates a smaller subset from the complete collection.


Derived State

Notice:

const totalPages =
Math.ceil(users.length / PAGE_SIZE);

This value is derived from existing state.

React Learn recommends:

Avoid redundant state.

Instead of storing total pages separately, we calculate it from existing data.

Benefits:

  • Less code
  • Fewer bugs
  • Easier maintenance
  • Better synchronization

Loading State

The loading flag improves user experience.

const [loading, setLoading] =
useState(true);

While data is loading:

<Spinner label="Loading users..." />

The user immediately understands that work is being performed.

This is a common enterprise pattern.


UserTable Component

The table component receives:

users: User[]

and renders:

Name
Email
Phone

using Fluent UI Table components.

The component is completely reusable because it only receives data through props.

This follows React’s concept of pure components.


PaginationBar Component

The PaginationBar component receives:

currentPage
totalPages
onPrevious
onNext

It does not know where the data comes from.

Its only responsibility is:

Display navigation controls

This is a perfect example of separation of concerns.


Enterprise Benefits of Pagination

Without pagination:

1,000 records
→ huge table
→ poor performance
→ difficult navigation

With pagination:

1,000 records
→ smaller pages
→ faster rendering
→ easier navigation

This is why nearly every enterprise system implements paging.


Understanding main.tsx

The application entry point:

import React from "react";
import ReactDOM from "react-dom/client";
import {
FluentProvider,
webLightTheme,
} from "@fluentui/react-components";
import App from "./App";
import "./index.css";
ReactDOM.createRoot(
document.getElementById("root")!
).render(
<React.StrictMode>
<FluentProvider theme={webLightTheme}>
<App />
</FluentProvider>
</React.StrictMode>
);

Responsibilities:

  • Connect React to HTML
  • Enable Fluent UI
  • Apply Microsoft theme
  • Start the application

Understanding index.css

body {
margin: 0;
font-family: "Segoe UI", Arial, sans-serif;
background-color: #f5f5f5;
}
* {
box-sizing: border-box;
}
button {
font-family: inherit;
}
table {
width: 100%;
}
.app-container {
min-height: 100vh;
padding: 32px;
background-color: #f5f5f5;
}
.app-content {
max-width: 1100px;
margin: 0 auto;
}
.app-header {
margin-bottom: 24px;
}
.pagination-wrapper {
display: flex;
justify-content: center;
margin-top: 24px;
}

This CSS:

  • Removes browser defaults
  • Applies Microsoft typography
  • Creates consistent spacing
  • Centers content
  • Supports responsive layouts

Technical Summary

ConceptExplanation
useStateStores page and user data
useEffectLoads external API data
Fetch APIRetrieves remote data
PaginationDivides datasets into pages
Derived StateCalculates total pages
Fluent UI TableDisplays enterprise data
Fluent UI ButtonNavigation controls
SpinnerLoading indicator
Service LayerAPI abstraction
TypeScript InterfaceStrongly typed data

Official Documentation

React

  • React Learn
  • State: A Component’s Memory
  • Synchronizing with Effects
  • You Might Not Need an Effect

Fluent UI

  • Fluent UI React Components
  • Fluent UI Table
  • Fluent UI Button

Vite

  • Vite Guide

TypeScript

  • TypeScript Documentation

Final Architectural Insight

Pagination demonstrates one of the most important React principles:

Data remains the same
State decides what portion is visible
React renders the result

The dataset is never modified.

Instead:

Current Page
→ determines visible records
→ React re-renders
→ UI updates

This same architectural pattern appears in:

  • DataGrid systems
  • SharePoint lists
  • CRM dashboards
  • Reporting portals
  • Administrative systems
  • Enterprise search results

Mastering pagination prepares you for larger applications where thousands of records must be displayed efficiently.

Current Progress

BlockAppNameStatus
Block 461REST API ConsumptionCompleted
Block 462Dashboard with APICompleted
Block 463Async SearchCompleted
Block 464GitHub User ExplorerCompleted
Block 465Weather AppCompleted
Block 466Pagination SystemCompleted
Block 467Infinite ScrollNext

Apps completed: 01–66
Current app: 66 — Pagination System
Next app: 67 — Infinite Scroll

Edvaldo Guimrães Filho Avatar

Published by