Uncaught TypeError: Cannot read properties of undefined (reading 'img')

Viewed 263

ProductDetail.js file

import React from 'react'
import { useParams } from 'react-router-dom'
import DATA from '../Data';

const ProductDetail = () => {
  {/*Now we need a product id which is pass from the product page*/}
  const proid=useParams();
  const proDetail=DATA.filter(x=>x.id===proid.id)
  const product=proDetail[0]
  console.log(product)

  return (
    <>
      <div className='container my-5 py-3'>
        <div className='row'>
          <div className='col-md-6'>
            <img src={product.img} alt={product.title} />
          </div>
          <div className="col-md-6">
            <h1>{product.title}</h1>
            <hr />
            <h2>{product.price}</h2>
            <p>{product.desc}</p>
            <button className='btn btn-outline-primary'>Add to cart</button>
          </div>
        </div>
      </div>
    </>
  )
}

export default ProductDetail

App.js file

import './App.css';
import Header from './components/Header';
import {BrowserRouter, Routes,Route} from 'react-router-dom'
import Home from './components/Home';
import Product from './components/Product';
import About from './components/About';
import Contact from './components/Contact';
import Footer from './components/Footer';
import ProductDetail from './components/ProductDetail';


function App() {
  return (
    <div>
      <BrowserRouter>
        <Header/>
        <Routes>
          <Route path='/' element={<Home/>}/>
          <Route path='/product' element={<Product/>}/>
          <Route path='/product/:id' element={<ProductDetail/>}/>
          <Route path='/about' element={<About/>}/>
          <Route path='/contact' element={<Contact/>}/>
        </Routes>
        <Footer/>
      </BrowserRouter>
    </div>
  );
}

export default App;

Data.js file

const DATA=[
    {
        id: 0,
        title: 'Apple iPhone 11',
        price: 49900,
        desc: '6.1-inch (15.4 cm diagonal) Liquid Retina HD LCD display Water and dust resistant (2 meters for up to 30 minutes, IP68) Dual-camera system with 12MP Ultra Wide and Wide cameras; Night mode, Portrait mode, and 4K video up to 60fps 12MP TrueDepth front camera with Portrait mode, 4K video, and Slo-Mo Face ID for secure authentication A13 Bionic chip with third-generation Neural Engine Fast-charge capable',
        img: '/iphone1.jpg'
    },
    {
        id: 1,
        title: 'Apple iPhone 12 (128GB) - Blue',
        price: 58999,
        desc: '6.1-inch (15.5 cm diagonal) Super Retina XDR display Ceramic Shield, tougher than any smartphone glass A14 Bionic chip, the fastest chip ever in a smartphoneAdvanced dual-camera system with 12MP Ultra Wide and Wide cameras; Night mode, Deep Fusion, Smart HDR 3, 4K Dolby Vision HDR recording 12MP TrueDepth front camera with Night mode, 4K Dolby Vision HDR recording.Industry-leading IP68 water resistance.Supports MagSafe accessories for easy attach and faster wireless charging.iOS with redesigned widgets on the Home screen, all-new App Library, App Clips and more',
        img: '/blueapple.jpg'
    },
    {
        id: 2,
        title: 'Apple iPhone 11 (64GB) - (Product) RED',
        price: 47999,
        desc: '6.1-inch (15.4 cm diagonal) Liquid Retina HD LCD display Water and dust resistant (2 meters for up to 30 minutes, IP68).Dual-camera system with 12MP Ultra Wide and Wide cameras; Night mode, Portrait mode, and 4K video up to 60fps. 12MP TrueDepth front camera with Portrait mode, 4K video, and Slo-Mo Face ID for secure authentication.A13 Bionic chip with third-generation Neural EngineFast-charge capable',
        img: '/red.jpg'
    }
]

export default DATA
3 Answers

Issue

The path='/product/:id' id path param will be a String type in the component.

const { id } = useParams(); // <-- id is a String

The id property in your DATA is a Number type.

const DATA = [
  {
    id: 0, // <-- id is a Number
    ...
  },
  {
    id: 1, // <-- id is a Number
    ...
  },
  {
    id: 2, // <-- id is a Number
    ...
  }
]

This type mismatch causes the strict === equality check to fail in the ProductDetail component.

const proid = useParams();
const proDetail = DATA.filter(x => x.id === proid.id); // returns empty array
const product = proDetail[0]: // undefined
console.log(product);

Error is thrown at first attempt to access property X of undefined.

<img
  src={product.img} // <-- first access throws error!!
  alt={product.title}
/>

Solution

To use strict === equality ensure you are using a type safe comparison. You should convert all values to strings. You should also gracefully handle the case where the product isn't found in the data.

Example:

const ProductDetail = () => {
  const { id } = useParams();
  const product = DATA.find(x => String(x.id) === id);
  console.log(product);

  return (
    <div className='container my-5 py-3'>
      <div className='row'>
        {product
          ? (
            <>
              <div className='col-md-6'>
                <img src={product.img} alt={product.title} />
              </div>
              <div className="col-md-6">
                <h1>{product.title}</h1>
                <hr />
                <h2>{product.price}</h2>
                <p>{product.desc}</p>
                <button className='btn btn-outline-primary'>
                  Add to cart
                </button>
              </div>
            </>
          )
          : (
            <div className='col-md-12'>
              No product matched
            </div>
          )
        }
      </div>
    </div>
  );
};

You probably need to use object destructuring:

const {proid} = useParams();
Related