React 및 Tailwind CSS에서 고성능 동적 제품 필터 구성 요소 구축

작성자

카테고리:

← 피드로
DEV Community · Idan Bakal · 2026-06-24 개발(SW)

Idan Bakal

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;

Enter fullscreen mode Exit fullscreen mode

}, [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"
          /&gt;



          Category

            {CATEGORIES.map(category =&gt; (
               setSelectedCategory(category)}
                className="px-3 py-1.5 text-xs font-medium rounded-lg transition"
              &gt;
                {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"
          /&gt;



          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"
          &gt;
            Featured
            Price: Low to High
            Price: High to Low
            Highest Rated






          {filteredProducts.map(product =&gt; (


                <span>
                  {product.category}
                </span>
                <h3>{product.name}</h3>


                <span>${product.price}</span>
                <span>★ {product.rating}</span>


          ))}

Enter fullscreen mode Exit fullscreen mode

);
}

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.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다