Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React Router not rerendering page after it updates URL (UseNavigate or Link)

I have a shopping site built with React and React Router, There is a main shopping page and a product page for each product, the product page has a next page button that calls

const handleNext = () => {
  navigate(`/shop/product/${product.id + 1}`, { replace: true })
}

The URL changes but the page does not rerender and stays on the same product, if I refresh the page manually the page does update.

I have also tried using and it does the same thing

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

<Link to=`/shop/product/${product.id + 1}`>Next</Link> 

Although when I reroute to '/home' or '/contact' it works.

RouteSwitch.JS

import { BrowserRouter, Routes, Route } from "react-router-dom";
import HomePage from "./components/Homepage/Homepage";
import ShoppingPage from "./components/ShoppingPage/ShoppingPage";
import Nav from "./components/Nav/Nav";
import Contact from "./components/Contact/Contact";
import ProductPage from "./components/ProductPage/ProductPage";
import Checkout from "./components/Checkout/Checkout";

const RouteSwitch = (props) => {
  const { cart, setCart } = props.props;

  return (
    <BrowserRouter>
      <Nav cart={cart} />
      <Routes>
        <Route exact path="/" element={<HomePage />} />
        <Route path="/shop" element={<ShoppingPage />} />

        <Route
          exact
          path="/shop/product/:id"
          element={<ProductPage props={{ setCart, cart }} />}
        />

        <Route path="/contact" element={<Contact />} />
        <Route
          path="/checkout"
          element={<Checkout cart={cart} setCart={setCart} />}
        />
      </Routes>
    </BrowserRouter>
  );
};

export default RouteSwitch;

ProductPage.js

import { useLocation, useParams, useNavigate, Link } from "react-router-dom";
import { useEffect, useState } from "react";
import './ProductPage.css'
import data from "../toy-api/data"
import ProductMenu from "../ProductMenu/ProductMenu"

const ProductPage = (props) => {
  const { setCart, cart } = props.props;

  const getProdByID = (id) => data.find((item) => item.id === parseInt(id));
  const navigate = useNavigate();
  const params = useParams();
  const location = useLocation();
  const [product, setProduct] = useState({});
  const { fromShopRoute = false, prodProps = errorObj } = location.state || {};

  // Use Effect that runs when the COMP mounts
  useEffect((e) => {

      let _product = getProdByID(params.id);

      if (_product !== undefined) {
        setProduct(_product);
      }
      // If the search returns undefined it will set the Product
      // to an errorObj and reroute the user to shop page
      else {
        setProduct(errorObj);
        navigate("/shop");
      }
    }
  }, []);


  const handleNext = () => {
    navigate(`/shop/product/${product.id + 1}`, { replace: true })
  }

  return (
    <div>
      <div className="product-page-container">

        <div className="product-header">
          <h1>{product.name}</h1>
          <ProductMenu
            setCart={setCart}
            product={product} 
            setProduct={setProduct}
            cart={cart}
          >
          </ProductMenu>
        </div>


        <div className="img-container">
 
          <img
            className="product-img"
            loading="lazy"
            src={product.src}
            alt={product.name}
          />

          <div onClick={handleNext} className="slide-btn ">
            Next
          </div>

        </div>



      </div>

    </div >
  );
};

export default ProductPage;

I tried all sorts of "UseNavigate(0)" and other methods with useEffect watching the params.id but I have found that they are messy solutions that aren’t giving me my required goal.

>Solution :

The ProductPage remains mounted when the "/shop/product/:id" route path is matched and only the id path parameter is changing.

The useEffect hook for fetching data depends on the id route path param.

const { id } = useParams();

// Use Effect that runs on initial render and when id updates
useEffect(() => {
  let _product = getProdByID(id);

  if (_product !== undefined) {
    setProduct(_product);
  } else {
    // If the search returns undefined it will set the Product
    // to an errorObj and reroute the user to shop page
    setProduct(errorObj);
    navigate("/shop");
  }
}, [id]); // <-- add id dependency
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading