red_rum
red_rum

Reputation: 119

React route to a specific product details page from a product page

I have a product page, where if the user clicks on a specific product card, it will redirect the user to a new page where that specific product details will be displayed only. However, in my code, even after redirecting it to the details page, it still shows the entire product list on that page. I need a bit of help to solve this issue. I have tried passing props to differentiate. But it doesn't seem to work. My FeaturedProduct.js:

import React from "react";
import { useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import ProductDetails from "./ProductDetails";
import axios from "axios";

function FeaturedProduct(props) {
  const [products, setProducts] = useState([]);
 
  useEffect(() => {
    fetchProducts();
  }, []);

  function fetchProducts() {
    axios
      .get("https://shoppingapiacme.herokuapp.com/shopping") 
      .then((res) => {
        console.log(res); 
        setProducts(res.data);
      })
      .catch((err) => {
        console.log(err);
      });
  }
  return (
    <div>
      <h1> Your Products List is shown below:</h1>
      <div className="item-container">
       
        {products.map((product) => (
          <div className="card" key={product.id}>
            {" "}
           
            <h3>{product.item}</h3>
            <p>
              {product.city}, {product.state}
            </p>
            <Router>
              <Link to="/productdetails">More Details</Link>

              <Switch>
                <Route path="/productdetails">
                <ProductDetails product={product}/>
                </Route>
              </Switch>
            </Router>
          </div>
        ))}
      </div>
    </div>
  );
}

export default FeaturedProduct;

My ProductDetails.js:

function ProductDetails(props) {
const {name, color} = props.product;

  return (
    <div>
      <div>
        <h1>{name}</h1>
        <h1>{color}</h1>
      </div>
    </div>
  );
}
export default  ProductDetails;

My App.js:

import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import FeaturedProduct from "./FeaturedProduct";

import "./App.css";

function App() {
  return (
    <div className="App">
      <FeaturedProduct />
    </div>
  );
}

export default App;

Upvotes: 3

Views: 10984

Answers (1)

Drew Reese
Drew Reese

Reputation: 203208

Issue

You are rendering that same router/link/route for each mapped product element.

<Router>
  <Link to="/productdetails">More Details</Link>

  <Switch>
    <Route path="/productdetails">
      <ProductDetails product={product}/>
    </Route>
  </Switch>
</Router>

This means when the path is "/productdetails" you render a Route and ProductDetails component for each and every one of them.

A Solution

It is more common to render one single Router and Route for a product details page with either a specific product id as a route param or to pass entire product object in route state (though less common).

Move the Router into App to provide a single routing context to the app:

function App() {
  return (
    <Router>
      <div className="App">
        <FeaturedProduct />
      </div>
    </Router>
  );
}

Move the Switch and Route below the products mapping, leaving only the Link in the map callback. Link to a specific product id and use the Route's render prop to search for the matching product by id to pass in as a prop:

function FeaturedProduct(props) {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    fetchProducts();
  }, []);

  function fetchProducts() {
    axios
      .get("https://shoppingapiacme.herokuapp.com/shopping")
      .then((res) => {
        console.log(res);
        setProducts(res.data);
      })
      .catch((err) => {
        console.log(err);
      });
  }
  return (
    <div>
      <h1> Your Products List is shown below:</h1>
      <div className="item-container">
        {products.map((product) => (
          <div className="card" key={product.id}>
            <h3>{product.item}</h3>
            <p>
              {product.city}, {product.state}
            </p>
            <Link to={`/product/${product.id}`}>More Details</Link>
          </div>
        ))}
      </div>
      <Switch>
        <Route
          path="/product/:id"
          render={({ match }) => (
            <ProductDetails
              product={products.find(
                (product) => String(product.id) === match.params.id
              )}
            />
          )}
        />
      </Switch>
    </div>
  );
}

Edit react-route-to-a-specific-product-details-page-from-a-product-page

Upvotes: 1

Related Questions