'React js: fail to get specific product data when clicking on one product

The code below fail to get specific data when clicking on a product: In Product.js:

 <Link to={`/product/${item.id}`}>
     <p className='product_title'>{item.title}</p>
     </Link>

In App.js

 <Route path='/product/:id'>
        <Header />
        <DetailProductPage />
        </Route>

All the above seem work well, but the DetailProductPage has problems. code shown as below. The code successfully get {id} = useParams(), but the code fails to get the details. The code within the useEffect() does not work, and "fail to load" the data.

import React, { useEffect, useState } from 'react';
import { Col, Row } from 'antd';
import ProductImages from './ProductImages';
import ProductInfo from './ProductInfo';
import {productItems} from '../Data';
import { useParams } from 'react-router-dom';


function DetailProductPage() {

    const { id }=useParams();
    const [details, setDetails]=useState([])
    
    useEffect(() => {
       productItems.map((item) =>
       { 
           if (item.id === id) {
               return (setDetails(item))
           } else { console.log("fail to load")}
        })
     }, [id]);
        
    return (
      <div className="postPage" style={{width:'100%', padding: '3rem 4rem'}}>

         <div style={{display: 'flex', justifyContent:'center'}}>
             <h1>ID: {details.id}</h1>
         </div>

              
       </div>
   )
}

export default DetailProductPage


Solution 1:[1]

The common source of error with useParams is that everything is a string. If you want to make comparisons, you will have to cast it to the same type or use == for the comparison.

First Approach - Cast it to the same type

function DetailProductPage() {
    // id is a string
    const { id }=useParams();
    const [details, setDetails]=useState([])
    
    useEffect(() => {
       // Using find as it makes a nicer syntax
       setDetails(productItems.find(item => String(item.id) === id))
      // Or setDetails(productItems.find(item => item.id === Number(id)))
     }, [id]);
        
    return (
      <div className="postPage" style={{width:'100%', padding: '3rem 4rem'}}>

         <div style={{display: 'flex', justifyContent:'center'}}>
             <h1>ID: {details.id}</h1>
         </div>

              
       </div>
   )
}

Read more about find here

Second Approach - use ==

function DetailProductPage() {

    const { id }=useParams();
    const [details, setDetails]=useState([])
    
    useEffect(() => {
       setDetails(productItems.find(item => item.id == id))
     }, [id]);
        
    return (
      <div className="postPage" style={{width:'100%', padding: '3rem 4rem'}}>

         <div style={{display: 'flex', justifyContent:'center'}}>
             <h1>ID: {details.id}</h1>
         </div>

              
       </div>
   )
}

If the above approaches doesn't work for you here is a working example. This is using router-router-dom version 6.

import { BrowserRouter, Route, Routes, useParams } from "react-router-dom";
import { useEffect, useState } from "react";

const products = [
  { id: 1, content: "Hello 1" },
  { id: 2, content: "Hello 2" },
  { id: 3, content: "Hello 3" }
];

export const Details = () => {
  const { id } = useParams();
  const [product, setProduct] = useState();

  useEffect(() => {
    setProduct(products.find((item) => item.id === Number(id)));
  }, [id]);

  return <pre>{JSON.stringify(product, null, 2)}</pre>;
};

export default function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/product/:id" element={<Details />} />
      </Routes>
    </BrowserRouter>
  );
}

Edit adoring-pasteur-cltufs

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 kwaku hubert