Search code examples
javascriptreactjsreact-routerreact-router-dom

How does React-Router determine which path to follow?


For reference, the Layout is returning a Link tag which is as follows:

<Link to="about">About</Link>

Therefore it is a relative path. So when I'm clicking the "about" link, it is getting a URL relative to the current path so my final URL would be "http://localhost:3000/about" that means that react-router will first look for the route that has a path of "/", and then look for a route that has a path of "about". But in the code below, I've placed the "about" route outside the route that has the path "/" and despite this, my About component is rendering.

Why is that happening? I'm quite confused on the topic of how react-router determines which path to follow and thus which component will be rendered.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { BrowserRouter, Routes, Route } from "react-router-dom"
import Home from './Home'
import About from './About';
import Layout from './components/Layout';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>  
    <Routes>
      <Route path='/' element={<Layout />}>
        <Route index element={<Home />} />
        <Route path='drinks' element={<GetDrinks />} />
        <Route path='drinks/:drink' element={<FetchDrink />} />
        <Route path='host' element={<HostLayout />}>
          <Route path='dashboard' index element={<Dashboard />} />
          <Route path='income' element={<Income />} />
          <Route path='reviews' element={<Reviews />} />
        </Route>
      </Route>
      <Route path='about' element={<GetDrinks />} />
    </Routes>
  </BrowserRouter>
);        

Solution

  • All routes are assumed to start from root, e.g. "/". So given the About page is a root level route, it will be rendered relative to the root, e.g. "/about".

    <BrowserRouter>
      <Routes>
        <Route path='/' element={<Layout />}>
          <Route index element={<Home />} />
          <Route path='drinks' element={<GetDrinks />} />
          <Route path='drinks/:drink' element={<FetchDrink />} />
          <Route path='host' element={<HostLayout />}>
            <Route path='dashboard' index element={<Dashboard />} />
            <Route path='income' element={<Income />} />
            <Route path='reviews' element={<Reviews />} />
          </Route>
        </Route>
        <Route path='about' element={<GetDrinks />} /> // <-- Matches "/about"
      </Routes>
    </BrowserRouter>
    

    is the same as explicitly specifying the full paths

    <BrowserRouter>
      <Routes>
        <Route path='/' element={<Layout />}>
          <Route index element={<Home />} />
          <Route path='/drinks' element={<GetDrinks />} />
          <Route path='/drinks/:drink' element={<FetchDrink />} />
          <Route path='/host' element={<HostLayout />}>
            <Route path='/host/dashboard' index element={<Dashboard />} />
            <Route path='/host/income' element={<Income />} />
            <Route path='/host/reviews' element={<Reviews />} />
          </Route>
        </Route>
        <Route path='/about' element={<GetDrinks />} />
      </Routes>
    </BrowserRouter>
    

    Being able to use relative paths in the routing configuration is basically allowing you to write more succinct code and make maintaining the code easier if you want to move routes around, i.e. if you wanted to move all the "/host/*" routes to "/guest/*" you only need to change the parent layout route from "/host" to "/guest" and all the nested routes automagically get the correct path.

    Note:

    This route matching should not be confused with the "absolute"-ness vs "relative"-ness of navigation links/targets. Using an absolute link target <Link to="/about">About</Link> the link will always navigate to "/about" regardless of where the link is rendered within the routing tree, but using a relative link target <Link to="about">About</Link> will only append relative to the path for whatever the path is where the link is rendered.

    For example:

    • When <Link to="about">About</Link> is rendered in the root Layout component rendered on "/" then the link correctly navigates to "/about".
    • If/when <Link to="about">About</Link> is rendered more deeply, like in the HostLayout rendered on "/host", the result would be a navigation to "/host/about". Or if rendered in Dashboard, the result would be "/host/dashboard/about".