menu

Questions & Answers

Link tag not working in React Router v6.7

React router v6.7 does add /about to the end of the url but doesn't render the components. Normally putting the url does work though.

Navbar.js:

import React from 'react'
import PropTypes from 'prop-types'
import { Link, BrowserRouter } from 'react-router-dom'
export default function Navbar(props) {
    return (
        <BrowserRouter>
            <nav className={`navbar navbar-expand-lg navbar-${props.mode} bg-${props.mode}`}>
                <div className="container-fluid">
                    <Link className="navbar-brand" to="/">{props.title}</Link>
                    <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                        <span className="navbar-toggler-icon"></span>
                    </button>
                    <div className="collapse navbar-collapse" id="navbarSupportedContent">
                        <ul className="navbar-nav me-auto mb-2 mb-lg-0">
                            <li className="nav-item">
                                <Link className="nav-link active" aria-current="page" to="/">Home</Link>
                            </li>
                            <li className="nav-item">
                                <Link className="nav-link" to="/about">{props.aboutText}</Link>
                            </li>
                            <li className="nav-item dropdown">
                                <Link className="nav-link dropdown-toggle" to="/" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                                    Dropdown
                                </Link>
                                <ul className="dropdown-menu" aria-labelledby="navbarDropdown">
                                    <li><Link className="dropdown-item" to="/">Action</Link></li>
                                    <li><Link className="dropdown-item" to="/">Another action</Link></li>
                                    <li><hr className="dropdown-divider" /></li>
                                    <li><Link className="dropdown-item" to="/">Something else here</Link></li>
                                </ul>
                            </li>
                            <li className="nav-item">
                                <Link to="/" className="nav-link disabled">Disabled</Link>
                            </li>
                        </ul>
                        <div className="form-check form-switch mx-3">
                            <input className="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckDefault" onClick={props.toggleDarkMode} />
                            <label className="form-check-label" htmlFor="flexSwitchCheckDefault">Dark Mode</label>
                        </div>
                        <form className="d-flex">
                            <input className="form-control me-2" type="search" placeholder="Search" aria-label="Search" />
                            <button className="btn btn-outline-success" type="submit">Search</button>
                        </form>
                    </div>
                </div>
            </nav>
        </BrowserRouter>
    )
}
Navbar.propTypes = {
    title: PropTypes.string.isRequired,
    aboutText: PropTypes.string
}

Navbar.defaultProps = {
    title: "Enter your Title",
    aboutText: "About"
}

App.js

// import logo from './logo.svg';
import { useState } from 'react';
import './App.css';
import About from './components/About';
import Navbar from './components/Navbar';
import TextForm from './components/TextForm';

import {
  createBrowserRouter,
  RouterProvider,
} from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <TextForm />,
  },
  {
    path: "/about",
    element: <About />
  }
]);

function App() {
  const [mode, setMode] = useState("light");
  const toggleDarkMode = (event) => {
    if (event.target.checked) {
      setMode("dark");
      document.body.style.backgroundColor = "#15181a";
      document.body.style.color = "white";
    }
    else {
      setMode("light");
      document.body.style.backgroundColor = "white";
      document.body.style.color = "black";
    }
  }
  return (
    <>
      <Navbar title="TextUtils" aboutText="About Us" mode={mode} toggleDarkMode={toggleDarkMode} />
      <RouterProvider router={router} />
    </>
  );
}

export default App;

Expectation: Link to should render the component into the DOM without reloading.

Reality: The url gets concatenated but the page actually doesn't render anything.

Comments:
2023-01-19 23:10:04
You don't appear to have actually defined any routes inside your app - you just have links, but don't specify anywhere what components should be rendered at those routes. I think you need to have a closer look at the docs.
2023-01-19 23:10:04
I have added routes to App.js and imported NavBar.js into it to render do I have attached the App.js too. Do I need to add routes to NavBar.js too?
2023-01-19 23:10:04
no you don't - thanks for editing, it wasn't clear that you had any such code. Particularly as you have a <BrowserRouter> inside NavBar which I don't believe is needed. Does the problem get fixed if you simply remove that? (I wish I had more experience with React Router - I've used it in one previous project but I'm not familiar at all with the newer v6 API, and the docs don't seem to be the clearest! This page though suggests that you don't need a BrowserRouter when you're already using createBrowserRouter.)
Answers(1) :

Your <RouterProvider /> needs to wrap the NavBar component with router prop. Check out the official documentation.

What you're currently doing is wrapping the Navbar but you have provided no router instance. So it doesn't know the routes and which component to render when routes change.

Refactor App.js like this:

 <>
    <RouterProvider router={router}>
<Navbar title="TextUtils" aboutText="About Us" mode={mode} toggleDarkMode={toggleDarkMode} />
    </RouterProvider>
    </>

And remove RouterProvider parent component from Navbar