In modern e-commerce applications, user experience is everything. Users expect to filter through hundreds of products instantly without irritating page reloads. A lagging or poorly designed filter UI can directly impact conversion rates.
In this tutorial, we will build a production-ready, highly responsive Dynamic Product Filter Component from scratch using React (with state optimization) and Tailwind CSS for slick, modern styling.
Step 1: The Product Data Structure
First, let's define our mock product database structure. Create a file named data.js or keep it inside your component:
export const PRODUCTS_DATA = [
{ id: 1, name: "UltraFit Running Shoes", category: "Footwear", price: 120, rating: 4.8 },
{ id: 2, name: "Pro-Grip Training Gloves", category: "Accessories", price: 35, rating: 4.5 },
{ id: 3, name: "AirWeave Sports Hoodie", category: "Apparel", price: 75, rating: 4.6 },
{ id: 4, name: "Pulse Smart Fitness Watch", category: "Electronics", price: 240, rating: 4.9 },
{ id: 5, name: "Apex Cushion Sneakers", category: "Footwear", price: 150, rating: 4.2 },
{ id: 6, name: "Thermal Hydro Flask", category: "Accessories", price: 45, rating: 4.7 }
];
export const CATEGORIES = ["All", "Footwear", "Apparel", "Accessories", "Electronics"];
Step 2: Implementing the Core Filter Component
We will utilize the useMemo hook from React to ensure maximum performance. This caches the filtered results and only recalculates them when our criteria actually change, preventing unnecessary re-renders.
Here is the complete code for ProductFilter.jsx:
import React, { useState, useMemo } from 'react';
const PRODUCTS_DATA = [
{ id: 1, name: "UltraFit Running Shoes", category: "Footwear", price: 120, rating: 4.8 },
{ id: 2, name: "Pro-Grip Training Gloves", category: "Accessories", price: 35, rating: 4.5 },
{ id: 3, name: "AirWeave Sports Hoodie", category: "Apparel", price: 75, rating: 4.6 },
{ id: 4, name: "Pulse Smart Fitness Watch", category: "Electronics", price: 240, rating: 4.9 },
{ id: 5, name: "Apex Cushion Sneakers", category: "Footwear", price: 150, rating: 4.2 },
{ id: 6, name: "Thermal Hydro Flask", category: "Accessories", price: 45, rating: 4.7 }
];
const CATEGORIES = ["All", "Footwear", "Apparel", "Accessories", "Electronics"];
export default function ProductFilter() {
const [searchQuery, setSearchQuery] = useState('');
const [selectedCategory, setSelectedCategory] = useState('All');
const [maxPrice, setMaxPrice] = useState(300);
const [sortBy, setSortBy] = useState('featured');
const filteredProducts = useMemo(() => {
let result = [...PRODUCTS_DATA];
if (searchQuery.trim() !== '') {
result = result.filter(p => p.name.toLowerCase().includes(searchQuery.toLowerCase()));
}
if (selectedCategory !== 'All') {
result = result.filter(p => p.category === selectedCategory);
}
result = result.filter(p => p.price <= maxPrice);
if (sortBy === 'price-low') result.sort((a, b) => a.price - b.price);
else if (sortBy === 'price-high') result.sort((a, b) => b.price - a.price);
else if (sortBy === 'rating') result.sort((a, b) => b.rating - a.rating);
return result;
}, [searchQuery, selectedCategory, maxPrice, sortBy]);
return (
<h1>Discover Products</h1>
<p>Filter and find exactly what you need in real-time.</p>
Search
setSearchQuery(e.target.value)}
placeholder="Search products..."
className="w-full px-4 py-2 bg-slate-50 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
/>
Category
{CATEGORIES.map(category => (
setSelectedCategory(category)}
className="px-3 py-1.5 text-xs font-medium rounded-lg transition"
>
{category}
))}
Max Price
<span>${maxPrice}</span>
setMaxPrice(Number(e.target.value))}
className="w-full h-2 bg-slate-100 rounded-lg appearance-none cursor-pointer accent-blue-600"
/>
Sort By
setSortBy(e.target.value)}
className="w-full px-3 py-2 bg-slate-50 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
>
Featured
Price: Low to High
Price: High to Low
Highest Rated
{filteredProducts.map(product => (
<span>
{product.category}
</span>
<h3>{product.name}</h3>
<span>${product.price}</span>
<span>★ {product.rating}</span>
))}
);
}
Conclusion
By leveraging optimization hooks, we ensure that sorting and filtering are computed only when dependencies update, maintaining a rock-solid user experience. This architecture scales perfectly for e-commerce needs.
Top comments (0)