javascriptreactjsreact-routerreact-router-dom

Why is React-Router not rendering a route when I add its path to the end of the localhost:3000 URL?


I've been working through this React tutorial and have gotten stuck. (Chapter 16: React Router). My basic boilerplate html components all render properly in App.js UNTIL I wrapped some inside <Routes> tags and added the path="" and element={} attributes. The code below of my App.js file is where I'm at (05:00:38 in the tutorial video)

Note: You'll notice right away that I've already addressed problems and changed some code to overcome discrepancies between the tutorial video (which was made in 2021) and changes made in 2022 to React Router 6. These revisions included changing components to elements, Switch to Routes, etc. In retrospect I realize now I should have picked a more recent tutorial but here we are...

import Header from './Header';
import Nav from './Nav';
import Footer from './Footer';
import Home from './Home';
import NewPost from './NewPost';
import PostPage from './PostPage';
import About from './About';
import Missing from './Missing';
import { Router, Route, Routes, useHistory } from 'react-router-dom';
import { useState, useEffect } from 'react';

function App() {
  return (
    <div className="App">
      <Header />
      <Nav />
      <Routes>
        <Route path="" element={<Home />} />
        <Route path="post" element={<NewPost />} />
        <Route path="post/:id" element={<PostPage />} />
        <Route path="about" element={<About />} />
        <Route path="*" element={<Missing />} />
      </Routes>
      <Footer />
    </div>
  );
}

export default App;

Everything seems fine, i.e. only Header, Nav, Home, and Footer are rendering on "localhost:3000".

Screenshot of localhost:3000

The problem is when I go to "localhost:3000/post: to test and see if Home gets swapped out and re-rendered as NewPost per the tutorial. Instead, I get a blank screen. The same blank screen occurs when I try to navigate to "localhost:3000/post/:1" or "localhost:3000/about".

I suspect the problem lies somewhere in the App.js file above, my index.js file (below), or my NewPost.js file (below that):

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

ReactDOM
  .createRoot(document.getElementById('root'))
  .render(
    <Router>
      <Routes>
        <Route path="/" element={<App />} />
      </Routes>  
    </Router>
  );
import React from 'react'

const NewPost = () => {
  return (
    <main>
      <h1>NewPost</h1>
    </main>
  )
}

export default NewPost

I've searched Stack Overflow and found a few similar problems, mainly: DOM does not render when adding a nested route in react router. Why would this be happening? and react-router-dom <routes> not rendering anything in localhost:3000. Unfortunately I haven't yet found a fix. Several people suggested removing the exact keyword, which I did since it's since been removed/deprecated, but it didn't help. (Those previous issues ended up being resolved by making the React Router 6 syntax updates I noted at the beginning of my post.)

I've uploaded my full codebase here in case it's helpful: https://github.com/pudgyturtle/react-blog I can't for the life of me figure out what the problem is.


Solution

  • In React-Router-DOM 6 all routes are exactly matched by path, and the root "/" route rendering App doesn't allow for matching descendent routes.

    You can resolve this by appending the wildcard/splat "*" matcher to the root route:

    <Route path="/*" element={<App />} />
    

    Which allows the descendent routes to also be matched.

    That said, this root route isn't useful at all, you should just render App directly under the BrowserRouter and then the Routes and Route components rendered by App will work as root-level routes.

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import { BrowserRouter as Router } from 'react-router-dom';
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <Router>
        <App />
      </Router>
    );
    
    function App() {
      return (
        <div className="App">
          <Header />
          <Nav />
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="post" element={<NewPost />} />
            <Route path="post/:id" element={<PostPage />} />
            <Route path="about" element={<About />} />
            <Route path="*" element={<Missing />} />
          </Routes>
          <Footer />
        </div>
      );
    }