How to display only the item that was clicked on? React

Hi, I started building my own project (e-commerce react app), but I don’t know how to make the app display the specific item (along with its details) that was clicked on. I tried asking at StackOverflow and googled tons of codes, but nothing really helped. I’ve come a very long way and can’t move at all now.

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
import VinylClocks from './Components/VinylClocks.jsx';
import CustomClocks from './Components/CustomClocks.jsx';
import About from './Components/About.jsx';
import Contact from './Components/Contact.jsx';
import ProductPage from './Components/ProductPage.jsx';
import './index.css';
import {
  createBrowserRouter,
  RouterProvider,
  Route,
} from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <App/>,
  },
  {
    path: "vinylclocks",
    element: <VinylClocks/>,
  },
  {
    path: "customclocks",
    element: <CustomClocks/>,
  },
  {
    path: "about",
    element: <About/>,
  },
  {
    path: "contact",
    element: <Contact/>,
  },
  {
    path: "cart",
    element: <VinylClocks/>,
  },
  {
    path: "productpage/:productId",
    element: <ProductPage/>,
  },
]);

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>,
)
import React, { useEffect, useMemo, useState } from "react";
import "./VinylClocks.css";
import Navbar from "./Navbar.jsx";
import Footer from "./Footer.jsx";
import SortButton from "./SortButton.jsx";
import { data } from "./data.js";
import Product from "./Product.jsx";
import FilterButton from "./FilterButton.jsx";

export default function VinylClocks() {
  const [dataList, setDataList] = useState([]);
  const [selectedCategory, setSelectedCategory] = useState("");
  const [sortOption, setSortOption] = useState("latest");

  // Add default value on page load
  useEffect(() => {
    setDataList(data);
  }, []);

  // Function to get filtered and sorted list
  function getFilteredAndSortedList() {
    let filteredList = dataList;
    // Filter by category
    if (selectedCategory) {
      filteredList = dataList.filter((item) => item.cat === selectedCategory);
    }

    // Sort by 
    switch (sortOption) {
      case "highToLow":
        filteredList.sort((a, b) => b.price - a.price);
        break;
      case "lowToHigh":
        filteredList.sort((a, b) => a.price - b.price);
        break;
        case "oldest":
          filteredList.sort((a, b) => a.id - b.id);
        break;

      default:
        // Latest or default sorting
        case "latest":
        filteredList.sort((a, b) => b.id - a.id);
        break;
    }

    return filteredList;
  }

  // Avoid duplicate function calls with useMemo
  var filteredAndSortedList = useMemo(getFilteredAndSortedList, [
    selectedCategory,
    sortOption,
    dataList,
  ]);

  function handleCategoryChange(option) {
    setSelectedCategory(option);
  }

  function handleSortChange(option) {
    setSortOption(option);
  }

  return (
    <>
      <header className="header">
        <Navbar />
      </header>
      <div className="vc-container">
        <div className="filter-sort">
          <FilterButton onFilterChange={handleCategoryChange}/>
          <SortButton onSortChange={handleSortChange} />
        </div>
        <div className="products-container">
          <div className="catSort-container">
              <form onFilterChange={handleCategoryChange} className="cat-form" action="#">
                <h5>Categories:</h5>
                <input type="checkbox" checked={selectedCategory === ""} onChange={() => setSelectedCategory("")} id="all" className="radio-input" name="" value=""></input>
                <label htmlFor="all">All</label><br/>
                <input type="checkbox" checked={selectedCategory === "movies"} onChange={() => setSelectedCategory( "movies")} id="movies" className="radio-input" name="" value="movies"></input>
                <label htmlFor="movies">Movies</label><br/>
                <input type="checkbox" checked={selectedCategory === "music"} onChange={() => setSelectedCategory("music")} id="music" className="radio-input" name="" value="music"></input>
                <label htmlFor="music">Music</label><br/>
                <input type="checkbox" checked={selectedCategory === "sport"} onChange={() => setSelectedCategory("sport")} id="sport" className="radio-input" name="" value="sport"></input>
                <label htmlFor="sport">Sport</label><br/>
                <input type="checkbox" checked={selectedCategory === "other"} onChange={() => setSelectedCategory("other")} id="other" className="radio-input" name="" value="other"></input>
                <label htmlFor="other">Other</label>
            </form>
            <form onSortChange={handleSortChange} className="sort-form" action="#">
                <h5>Sort by:</h5>
                <h3>Date:</h3>
                <input type="checkbox" checked={sortOption === "latest"} onChange={() => setSortOption("latest")}  
                       id="latest" className="radio-input" name="" value="latest"></input>
                <label>Latest</label><br/>
                <input type="checkbox" checked={sortOption === "oldest"} onChange={() => setSortOption( "oldest")} 
                       id="oldest" className="radio-input" name="" value="oldest"></input>
                <label>Oldest</label><br/>
                <h3>Price:</h3>
                <input type="checkbox" checked={sortOption === "highToLow"} onChange={() => setSortOption("highToLow")} 
                       id="lowest" className="radio-input" name="" value="highToLow"></input>
                <label>Highest</label><br/>
                <input type="checkbox" checked={sortOption === "lowToHigh"} onChange={() => setSortOption( "lowToHigh")} 
                       id="highest" className="radio-input" name="" value="lowToHigh"></input>
                <label>Lowest</label>
                
            </form>
          </div>
            <div className="products">
              {filteredAndSortedList.map((item, id) => (
                <Product {...item} key={id} />
              ))}
              </div>
        </div>
      </div>
      <Footer />
    </>
  );
}
import React from "react";
import "./VinylClocks.css";
import { Link } from "react-router-dom";

export default function Product({id, name, price, img}) {
    return (

            <div className="products-card">
                <div className="name-price-tag">
                <Link to={`/productpage/${id}`}><img src={img}/></Link>
                <div className="price-container">
                    <p className="product-name">{name}</p>
                    <span className="price">${price}</span>
                </div>
            </div>   
            </div>
    )        
}
import React from "react";
import "./ProductPage.css";
import { data } from "./data.js";
 

export default function ProductPage() {

    return (

           <>
            {data.map((element, id) => (
            <div className="productPage-container" key={id}>

                <div className="image-container">
                    <img src={element.img} {...element}/>
                </div>
                <div className="about-product">
                    <span className="product-type">{element.type}</span>
                    <h2 className="product-name">{element.name}</h2>
                    <span className="product-price">{element.price}</span>
                    <p className="product-desc">{element.desc}</p>
                </div>
            </div>
            ))}
           </>
    )        
}

P.S. I know that the ProductPage component is just mapping over the array all over again, but that is the issue, i;m out of ideas on how should I achieve this. Also, I am using vite instead of cra, if it matters

I think you need to phrase this question more clearly. After reading the question and code, I mostly only have questions for you!

The design decisions are a little confusing for me. For example, when you click on the image link of a product it links to the products page? The products page maps a bunch of (I am assuming products though you call it only data/elements) elements but it never uses the Product component yet the VinylClocks component does map product components.

Would it be possible to learn more about what you are trying to do, what your expectations are and what is actually happening?

1 Like

It’s okay, found the solution.

1 Like