Search code examples
javascriptreact-routerreact-router-dom

Routing is failing using useParams


I am working on a small car e-shop project. I am trying to get the ProductDetails rendering in a new page when the user clicks on "more details" in Products, however, it is failing. First it is not showing the path at the browser bar which should be "http://localhost:3000/product-details" and second it is rendering the Home page.

App.js

import React from 'react';
import Cart from './pages/Cart';
import Home from './pages/Home';
import ProductDetails from './pages/ProductDetails';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { Navigate } from 'react-router-dom';

function App() { 
 return (
   <Router>
     <Routes>
       <Route>
         <Route path="/home" element={<Home />} />
         <Route path="/cart" element={<Cart />} />
         <Route path="/product-details/:id" element={<ProductDetails />} />
         <Route path="*" element={<Navigate to ="/home" replace />} />
       </Route>
     </Routes>
   </Router>
 );
}

export default App;

Products.js

import React from 'react';
import toyota from '../assets/images/toyota_camry2023.png'
import honda from '../assets/images/honda_civic2023.png';
import ford from '../assets/images/ford_mustang2023.png';
import { Link } from 'react-router-dom';

function Products() {
  const cars = [
    { id: 1, name: 'Toyota Camry', price: 25000, img: toyota },
    { id: 2, name: 'Honda Civic', price: 27000, img: honda },
    { id: 3, name: 'Ford Mustang', price: 35000, img: ford },
  ]

  return (
    <div>
      <h2>Find The Best Deals</h2>
      <h2>Available Cars</h2>
      <ul>
        {cars.map(car => (
          <li key={car.id}>
            <img src={car.img} alt={car.name} />
            <h3>{car.name}</h3>
            <p>Price: ${car.price}</p>
            <Link to={`product-details/${car.id}`} target="_blank">More details</Link>
          </li>
        ))}
      </ul>
    </div>
  )
}

export default Products;

ProductDetails.js

import React from 'react';
import { useParams } from 'react-router-dom';

function ProductDetails() {
  const { id }  = useParams();

  const Product = {
    1: {
      Engine: '2.5L Inline-4 Gas',
      Drivetrain: 'Front-Wheel Drive', 
      Transmission: '8-Speed       Automatic', 
      Warranty: '5 Years / 100000 km'
    },
    2: {
      Engine: 'Turbocharged DOHC 16-valve Inline-4', 
      Drivetrain: 'Front-Wheel-Drive,',    
      Transmission: 'Continuously Variable Automatic', 
      Warranty: '3 Years / 60000 km'
    },
    3: {
      Engine: 'Intercooled Turbo Premium Unleaded I-4', 
      Drivetrain: 'Rear Wheel Drive with limited-slip differential', 
      Transmission: '10-speed automatic transmission', 
      Warranty: '3 years / 60000 km'
    },

  };

 const ProductDetails = Product[id];

 return (
    <div>
      <h2>Car Details</h2>
      <p>{ProductDetails.Engine}</p>
      <p>{ProductDetails.Drivetrain}</p>
      <p>{ProductDetails.Transmission}</p>
      <p>{ProductDetails.Warranty}</p>
      <button>Add to Cart</button>
      <button>Book a Test Drive</button>
    </div>
  )
}

export default ProductDetails;

Would you be able to help me sort this issue out. I tried changing the routing, checked the syntax, followed my tutorials, all with no success.


Solution

  • Issue

    The Product component is rendered by the Home component rendered on route path "/home" and uses relative link target paths. Relative paths work relative to the current URL path. When the current URL path is "/home" and a link target is to={`product-details/${car.id}`}, then the resulting navigation action will be to "/home/product-details/someIdValue". Since there is no explicit route path that matches the URL path, the path="*" wildcard matcher/"catch all" route is rendered and the UI redirects to "/home".

    Solution

    Use absolute link target paths. The difference between relative and absolute routes paths is that absolute paths start from root, e.g. "/". In other words, add a leading "/" character to your link target path values.

    Example:

    to={`/product-details/${car.id}`}
    

    Code:

    const cars = [
      { id: 1, name: 'Toyota Camry', price: 25000, img: toyota },
      { id: 2, name: 'Honda Civic', price: 27000, img: honda },
      { id: 3, name: 'Ford Mustang', price: 35000, img: ford },
    ]
    
    function Products() {
      return (
        <div>
          <h2>Find The Best Deals</h2>
          <h2>Available Cars</h2>
          <ul>
            {cars.map(car => (
              <li key={car.id}>
                <img src={car.img} alt={car.name} />
                <h3>{car.name}</h3>
                <p>Price: ${car.price}</p>
                <Link to={`/product-details/${car.id}`}>
                  More details
                </Link>
              </li>
            ))}
          </ul>
        </div>
      );
    }