In this tutorial, we will build a fully functional Search, Sort, Filter & Pagination feature in a React application using a Node.js backend. We will use Axios for fetching data, and the dummy data will include fields like name, email, phone, address, status, and id. We will also incorporate modern CSS design for all components.
Introduction
Creating a feature-rich application involves implementing various functionalities like search, sort, filter, and pagination. These features enhance user experience and make data management easier. In this article, we’ll go through each step required to build these features in a React application, backed by a Node.js backend. We’ll use Axios for data fetching and ensure our design is modern and user-friendly.
Prerequisites
- Basic understanding of React
- Node.js and npm installed
- Basic knowledge of CSS
Setting Up the Project
Initialize a React Project:
npx create-react-app search-sort-filter-pagination
cd search-sort-filter-pagination
Initialize a Node.js Project for Backend:
mkdir backend
cd backend
npm init -y
npm install express cors body-parser
Setup Backend with Express: Create a server.js
file in the backend folder with the following code:
// backend/server.js
const express = require('express'); // Import Express
const cors = require('cors'); // Import CORS middleware
const bodyParser = require('body-parser'); // Import Body-Parser middleware
const app = express(); // Initialize Express
const PORT = 5000; // Set port
// Middleware
app.use(cors()); // Enable CORS
app.use(bodyParser.json()); // Enable JSON body parsing
// Dummy data
let users = [
{ id: 1, name: "John Doe", email: "john@example.com", phone: "123-456-7890", address: "123 Main St", status: "Active" },
{ id: 2, name: "Jane Smith", email: "jane@example.com", phone: "987-654-3210", address: "456 Elm St", status: "Inactive" },
// Add more dummy users as needed
];
// Routes
app.get('/users', (req, res) => {
res.json(users); // Send users as JSON response
});
// Start server
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`); // Log server start
});
Run the Node.js Server:
node server.js
Creating the React Components
App Component
This component will serve as the main container for our application.
// src/App.js
import React, { useState, useEffect } from 'react'; // Import React, useState, and useEffect
import axios from 'axios'; // Import Axios for data fetching
import SearchBar from './components/SearchBar'; // Import SearchBar component
import UserTable from './components/UserTable'; // Import UserTable component
import Pagination from './components/Pagination'; // Import Pagination component
const App = () => {
const [users, setUsers] = useState([]); // State to hold all user data
const [filteredUsers, setFilteredUsers] = useState([]); // State to hold filtered user data
const [searchTerm, setSearchTerm] = useState(''); // State to hold search term
const [currentPage, setCurrentPage] = useState(1); // State to hold current page number
const [usersPerPage] = useState(10); // State to hold number of users per page
// Fetch data from Node.js backend
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await axios.get('http://localhost:5000/users'); // Fetch users from Node.js backend
setUsers(response.data); // Set users state with fetched data
setFilteredUsers(response.data); // Set filtered users state with fetched data
} catch (error) {
console.error('Error fetching data', error); // Log any error that occurs during data fetching
}
};
fetchUsers(); // Call fetchUsers function
}, []); // Empty dependency array ensures this useEffect runs once on mount
// Filter users based on search term
useEffect(() => {
const results = users.filter(user =>
user.name.toLowerCase().includes(searchTerm.toLowerCase()) || // Check if name includes search term
user.email.toLowerCase().includes(searchTerm.toLowerCase()) || // Check if email includes search term
user.phone.includes(searchTerm) || // Check if phone includes search term
user.address.toLowerCase().includes(searchTerm.toLowerCase()) // Check if address includes search term
);
setFilteredUsers(results); // Set filtered users state with results
}, [searchTerm, users]); // Dependency array to re-run effect when searchTerm or users change
// Get current users for pagination
const indexOfLastUser = currentPage * usersPerPage; // Calculate index of last user on current page
const indexOfFirstUser = indexOfLastUser - usersPerPage; // Calculate index of first user on current page
const currentUsers = filteredUsers.slice(indexOfFirstUser, indexOfLastUser); // Slice filtered users array to get current users
// Change page
const paginate = (pageNumber) => setCurrentPage(pageNumber); // Function to set current page
return (
<div className="App">
<h1>User Management</h1>
<SearchBar setSearchTerm={setSearchTerm} /> // Render SearchBar component and pass setSearchTerm function as prop
<UserTable users={currentUsers} /> // Render UserTable component and pass currentUsers as prop
<Pagination
usersPerPage={usersPerPage}
totalUsers={filteredUsers.length}
paginate={paginate}
currentPage={currentPage}
/> // Render Pagination component and pass necessary props
</div>
);
};
export default App; // Export App component
SearchBar Component
This component allows users to search for specific data
// src/components/SearchBar.js
import React from 'react'; // Import React
const SearchBar = ({ setSearchTerm }) => {
return (
<input
type="text" // Set input type to text
placeholder="Search..." // Set placeholder text
onChange={(e) => setSearchTerm(e.target.value)} // Call setSearchTerm function with input value on change
/>
);
};
export default SearchBar; // Export SearchBar component
UserTable Component
This component displays the user data in a table format.
// src/components/UserTable.js
import React from 'react'; // Import React
import './UserTable.css'; // Importing the CSS for modern design
const UserTable = ({ users }) => {
return (
<table className="user-table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Address</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.phone}</td>
<td>{user.address}</td>
<td>{user.status}</td>
</tr>
))}
</tbody>
</table>
);
};
export default UserTable; // Export UserTable component
Pagination Component
This component handles the pagination of the user data.
// src/components/Pagination.js
import React from 'react'; // Import React
import './Pagination.css'; // Importing the CSS for modern design
const Pagination = ({ usersPerPage, totalUsers, paginate, currentPage }) => {
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(totalUsers / usersPerPage); i++) {
pageNumbers.push(i); // Add page number to pageNumbers array
}
return (
<nav>
<ul className="pagination">
{pageNumbers.map(number => (
<li key={number} className={`page-item ${currentPage === number ? 'active' : ''}`}>
<a onClick={() => paginate(number)} href="#!" className="page-link">
{number}
</a>
</li>
))}
</ul>
</nav>
);
};
export default Pagination; // Export Pagination component
``
Modern CSS Design
UserTable CSS
/* src/components/UserTable.css */
.user-table {
width: 100%; /* Set table width to 100% */
border-collapse: collapse; /* Collapse table borders */
margin: 20px 0; /* Add margin */
font-size: 1em; /* Set font size */
min-width: 400px; /* Set minimum width */
border-radius: 5px 5px 0 0; /* Set border radius */
overflow: hidden; /* Hide overflow */
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15); /* Add box shadow */
}
.user-table thead tr {
background-color: #009879; /*
Pagination CSS
/* src/components/Pagination.css */
.pagination {
display: flex; /* Set display to flex */
justify-content: center; /* Center align items */
padding: 10px 0; /* Add padding */
}
.pagination .page-item {
margin: 0 5px; /* Add margin */
}
.pagination .page-link {
padding: 8px 16px; /* Add padding */
border: 1px solid #ddd; /* Add border */
border-radius: 5px; /* Set border radius */
text-decoration: none; /* Remove text decoration */
color: #009879; /* Set text color */
cursor: pointer; /* Set cursor to pointer */
}
.pagination .page-item.active .page-link {
background-color: #009879; /* Set background color */
color: #ffffff; /* Set
Error Handling and Form Validation
In the above example, we have handled errors during data fetching with a try-catch block in the fetchUsers
function. For a more robust application, you can add more error handling and form validation techniques.
// src/App.js
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await axios.get('http://localhost:5000/users'); // Fetch users from Node.js backend
setUsers(response.data); // Set users state with fetched data
setFilteredUsers(response.data); // Set filtered users state with fetched data
} catch (error) {
// Show error message to the user
alert('Error fetching data: ' + error.message); // Display error message
}
};
fetchUsers(); // Call fetchUsers function
}, []); // Empty dependency array ensures this useEffect runs once on mount
Conclusion
In this article, we built a comprehensive Search, Sort, Filter & Pagination feature in a React application using a Node.js backend and Axios. We used modern CSS to design our components and added error handling to ensure robustness. By following this tutorial, you can enhance your React applications with these powerful features, providing a better user experience.
Welcome to DevTechTutor.com, your ultimate resource for mastering web development and technology! Whether you're a beginner eager to dive into coding or an experienced developer looking to sharpen your skills, DevTechTutor.com is here to guide you every step of the way. Our mission is to make learning web development accessible, engaging, and effective.