So I’m trying to build a logic which will enable user to see more details about the specific product that was clicked on, but I only managed to make it appear in the URL for now. How can I achieve this?
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/:name",
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({name, price, img}) {
return (
<div className="products-card">
<div className="name-price-tag">
<Link to={`/productpage/${name}`}><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’m aware that ProductPage is just mapping the array all over again, that ‘s what i’m trying to figure out.
2
Answers
You need to filter the product details based on the product name provided in the URL.
In
ProductPage
,Use the
useLocation
hook fromreact-router-dom
to access the current location. Extract the product name from the URL parameters usinglocation.pathname.split("/").pop()
.Use the
find
method to get the product from the data array that matches the extracted product name.If the product is not found, display a message like
"Product not found."
Use the
useParams
hook to access the product’sname
value from the route parameters.Use the current
name
parameter to search thedata
array for a matching element byname
property. Don’t forget to account for missing data.For details see: