Debarka Mondal
Debarka Mondal

Reputation: 53

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.

Upvotes: 0

Views: 840

Answers (2)

Debarka Mondal
Debarka Mondal

Reputation: 53

Ok, So the thing is React Router v6.7 docs for getting started does not mention that the elements inside the:

const router = createBrowserRouter(createRoutesFromElements(
  <Route path='/' element={<RootLayout />}>
    <Route index element={<TextForm />} />
    <Route path='/about' element={<About />} />
  </Route>
))

Would be rendered wherever the <Outlet /> tag is. So I made RootLayout page and put it inside that and everything works. Here is what it looks like.

import React from 'react'
import { Outlet } from 'react-router-dom'
import Navbar from '../components/Navbar'
import { useState } from 'react'

export default function RootLayout() {
    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} />
            <Outlet />
        </>
    )
}

Upvotes: 1

techoaman
techoaman

Reputation: 29

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

Upvotes: 0

Related Questions