DEV Community

Ben M
Ben M

Posted on

๐Ÿ›’ Building a Simple Product Page with React (Using Mock Data)

When you're building a React app, it's often easier to start with mock data before connecting to a real backend. In this post, Iโ€™ll show you how to set up a simple product page with:

  • Search ๐Ÿ”
  • Category + price filters ๐Ÿ’ฐ
  • Add/remove basket functionality ๐Ÿงบ

๐Ÿ“ Step 1: Add Your Main JSX Page

Create this file:

src/pages/ourProducts/Products.jsx
Enter fullscreen mode Exit fullscreen mode

Paste this code:

import { useState } from "react";
import ProductCard from "../../components/productCard/productCard.jsx";
import { products } from "../../data/products.js";
import "../ourProducts/ourProducts.css";

export default function Products() {
  const [basket, setBasket] = useState([]);
  const [searchTerm, setSearchTerm] = useState("");
  const [category, setCategory] = useState("");
  const [minPrice, setMinPrice] = useState("");
  const [maxPrice, setMaxPrice] = useState("");

  // Add item to basket
  const addToBasket = (product) => {
    setBasket((prev) => [...prev, product]);
  };

  // Remove item from basket
  const removeFromBasket = (indexToRemove) => {
    setBasket((prev) => prev.filter((_, i) => i !== indexToRemove));
  };

  // Filtering logic
  const filteredProducts = products.filter((p) => {
    const matchesSearch = p.name.toLowerCase().includes(searchTerm.toLowerCase());
    const matchesCategory = category === "" || p.category === category;
    const matchesMin = minPrice === "" || p.price >= parseFloat(minPrice);
    const matchesMax = maxPrice === "" || p.price <= parseFloat(maxPrice);

    return matchesSearch && matchesCategory && matchesMin && matchesMax;
  });

  return (
    <div className="productsPage">
      <h1>Our Products</h1>

      {/* Filters */}
      <div className="filters">
        <input
          type="text"
          placeholder="Search products..."
          value={searchTerm}
          onChange={(e) => setSearchTerm(e.target.value)}
        />

        <select value={category} onChange={(e) => setCategory(e.target.value)}>
          <option value="">All Categories</option>
          <option value="Fruits">Fruits</option>
          <option value="Dairy">Dairy</option>
          <option value="Bakery">Bakery</option>
        </select>

        <input
          type="number"
          placeholder="Min ยฃ"
          value={minPrice}
          onChange={(e) => setMinPrice(e.target.value)}
        />

        <input
          type="number"
          placeholder="Max ยฃ"
          value={maxPrice}
          onChange={(e) => setMaxPrice(e.target.value)}
        />
      </div>

      {/* Product Grid */}
      <div className="productGrid">
        {filteredProducts.map((p) => (
          <ProductCard key={p.id} product={p} onAdd={addToBasket} />
        ))}
      </div>

      {/* Basket */}
      <div className="basket">
        <h2>Basket ({basket.length})</h2>

        {basket.map((item, i) => (
          <div key={i} className="basketItem">
            <div>
              {item.name} โ€” ยฃ{item.price}
            </div>

            <button
              className="removeBtn"
              onClick={() => removeFromBasket(i)}
            >
              Remove
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฉ Step 2: Create the ProductCard Component

Create:

src/components/productCard/productCard.jsx
Enter fullscreen mode Exit fullscreen mode

Paste:

import "../productCard/productCard.css"

export default function ProductCard({ product, onAdd }) {
  return (
    <div className="productCard">
      <img src={product.image} alt={product.name} className="productImg" />

      <h3>{product.name}</h3>
      <p>{product.description}</p>

      <div className="productBottom">
        <span className="price">ยฃ{product.price}</span>
        <button onClick={() => onAdd(product)}>Add to basket</button>
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงช Step 3: Add Fake Data

Create:

src/data/products.js
Enter fullscreen mode Exit fullscreen mode

Paste:

export const products = [
  {
    id: 1,
    name: "Fresh Strawberries",
    category: "Fruits",
    description: "Sweet and juicy, 500g pack.",
    price: 3.50,
    image: "/images/strawberries.jpg"
  },
  {
    id: 2,
    name: "Aged Cheddar Cheese",
    category: "Dairy",
    description: "6 month matured, rich flavour.",
    price: 5.99,
    image: "/images/cheese.jpg"
  },
  {
    id: 3,
    name: "Organic Avocados",
    category: "Fruits",
    description: "Two pack, creamy texture.",
    price: 4.00,
    image: "/images/avocado.jpg"
  },
  {
    id: 4,
    name: "Flavoured Almond milk bundle",
    category: "Dairy",
    description: "Three pack, sustainably produced.",
    price: 3.75,
    image: "/images/almondMilk.jpg"
  },
  {
    id: 5,
    name: "Watermelon",
    category: "Fruits",
    description: "Ripe and fresh.",
    price: 4.00,
    image: "/images/watermelon.jpg"
  }
];
Enter fullscreen mode Exit fullscreen mode

`import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
plugins: [react()],
server: {
proxy: {
"/api": {
target: "http://127.0.0.1:5000",
changeOrigin: true,
secure: false,
},
},
},
optimizeDeps: {
include: ['react-fast-marquee']
}
});

`

๐Ÿ“‚ Suggested Folder Structure

src/
  components/
    productCard/
      productCard.jsx
      productCard.css
  data/
    products.js
  pages/
    ourProducts/
      Products.jsx
      ourProducts.css
Enter fullscreen mode Exit fullscreen mode

โš™๏ธ What You Get

Once everything is connected:

  • ๐Ÿ” Search products by name
  • ๐Ÿฅ‘ Filter by category (Fruits, Dairy, Bakery)
  • ๐Ÿ’ธ Filter by price range
  • ๐Ÿงบ Add/remove items from basket

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.