React-router-dom V6 don't change route correctly (refresh - f5 page is required)

Viewed 1506

I'm trying to apply basic route for my Reactjs app with functional component, and Material UI. I put <Link to .../> on navbar and expected when click Menu Item (Cart, Contact, Product) in navbar, content of page will change (just keep Header and Footer of page).

It is done with is worked, when click each Menu Item, URL change. But the page will not change, i have to reload page for content change. I don't understand why get this issue.

Image and details step of this issue: Step 1: When path is "/": Home Page Step 2: Click Menu Item (Our Product), URL change "/product" but page does not change: URL change Step 3: Have to reload page for see content of page change to component: Reload page

Below is my code and file structure:

App.js:

import "./App.css";
import Header from "./Header";
import Content from "./Content";
import Footer from "./Footer";
import Product from "./Product/Product";
import Contact from "./Contact";
import Cart from "./Cart";
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";

function App() {
  return (
    <div className="app">
      <Header />

      <Router>
        <Routes>
          <Route path="/" element={<Content />} />

          <Route path="/product" element={<Product />} />
          <Route path="/contact" element={<Contact />} />
          <Route path="/cart" element={<Cart />} />
        </Routes>
      </Router>

      <Footer />
    </div>
  );
}

export default App;

Header.js:

import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
const pages = ["Our Products", "Cart", "Contact"];
const settings = ["Profile", "Account", "Dashboard", "Logout"];
const links = ["/product", "/cart", "/contact"];

const Header = () => {
  return (
    <div className="app__header">
      . . .{/* render navbar */}
      <div className="header__nav">
        <Box
          sx={{
            gap: 20,
            flexGrow: 1,
            display: { xs: "none", md: "flex" },
          }}
        >
          {pages.map((page, index) => (
            <Link to={links[index]} textDecoration="none">
              <Button
                key={page}
                onClick={handleCloseNavMenu}
                sx={{ my: 2, color: "white", display: "block" }}
              >
                {page}
              </Button>
            </Link>
          ))}
        </Box>
      </div>
    </div>
  );
};

Product.js: (sample text for test)

import React from 'react'

function Product() {
  return (
    <div>Product</div>
  )
}

export default Product

Config.json:

{
  "name": "ecommerce-web-react",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@emotion/react": "^11.9.0",
    "@emotion/styled": "^11.8.1",
    "@mui/icons-material": "^5.6.2",
    "@mui/material": "^5.7.0",
    "@mui/x-data-grid": "^5.11.0",
    "@splidejs/react-splide": "^0.7.5",
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.2.0",
    "@testing-library/user-event": "^13.5.0",
    "lodash": "^4.17.21",
    "react": "^18.1.0",
    "react-dom": "^18.1.0",
    "react-router-dom": "^6.3.0",
    "react-scripts": "5.0.1",
    "swiper": "^8.1.4",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

Thanks for your help!

1 Answers

Move the Header component into the Router so the Link components it renders are working and updating the same routing context the routes are rendered in. There should have been an invariant warning/error regarding rendering the Link components outside a Router. If there is no such error/warning this is indicative of rendering the links into a separate router/routing context. You need only a single router for the entire app, so remove any other extraneous routers you might have in your app.

Example:

function App() {
  return (
    <div className="app">
      <Router>
        <Header /> // <-- move into Router
        <Routes>
          <Route path="/" element={<Content />} />
          <Route path="/product" element={<Product />} />
          <Route path="/contact" element={<Contact />} />
          <Route path="/cart" element={<Cart />} />
        </Routes>
      </Router>
      <Footer />
    </div>
  );
}
Related