Why is rendering the parent component and the child trying to enter the child component

Viewed 1360

Why is rendering the parent component and the child trying to enter the child component

"react-router-dom": "^6.0.1",

when I enter on the route:
http://localhost:3000/dashboard- the view work

http://localhost:3000/dashboard/employee - rendering dashboard and employee view (both views)

http://localhost:3000/dashboard/accounting - rendering dashboard and accounting view (both views)

Documentation:

https://reactrouter.com/docs/en/v6/getting-started/tutorial#nested-routes

index.js

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);

App.js

import AppRouter from "./routers/AppRouter";

function App() {
  return (
    <>
      <AppRouter />
    </>
  );
}

export default App;

AppRouter.js

import { Route, Routes } from "react-router-dom";
import Navbar from "../components/template/Navbar";
import AccountingHomeView from "../components/views/accounting/AccountingHomeView";
import DashboardHomeView from "../components/views/dashboard/DashboardHomeView";
import EmployeeHomeView from "../components/views/employee/EmployeeHomeView";
import HomeView from "../components/views/public/HomeView";
import LoginView from "../components/views/public/LoginView";

const AppRouter = () => {
  return (
    <div>
      <Navbar />
      <Routes>
        <Route path="/" element={<HomeView />} />
        <Route path="dashboard" element={<DashboardHomeView />}>
          <Route path="employee" element={<EmployeeHomeView />} />
          <Route path="accounting" element={<AccountingHomeView />} />
        </Route>
        <Route path="/login" element={<LoginView />} />
      </Routes>
    </div>
  );
};
export default AppRouter;

DashboardHomeView.js (with outlet)

import { Outlet } from "react-router-dom";

const DashboardHomeView = function () {
  return (
    <>
      <h1>DashboardHomeView</h1>
      <Outlet />
    </>
  );
};

export default DashboardHomeView;

component children Accounting

import React from "react";

const AccountingHomeView = function () {
  return (
    <div>
      <h1> Accountin</h1>
    </div>
  );
};
export default AccountingHomeView;
2 Answers

I also initially found this a bit confusing, but with nested routes the "parent" route is considered more of a "layout" component in that it is always rendered when its path matches, and renders all its children routes into its outlet.

const AppRouter = () => {
  return (
    <div>
      <Navbar />
      <Routes>
        <Route path="/" element={<HomeView />} />
        <Route
          path="dashboard"
          element={<DashboardHomeView />} // <-- always matched/rendered at "/dashboard*"
        > 
          <Route
            path="employee"
            element={<EmployeeHomeView />} // <-- conditionally matched/rendered
          />
          <Route
            path="accounting"
            element={<AccountingHomeView />} // <-- conditionally matched/rendered
          />
        </Route>
        <Route path="/login" element={<LoginView />} />
      </Routes>
    </div>
  );
};

const DashboardHomeView = function () {
  return (
    <>
      <h1>DashboardHomeView</h1> // <-- always matched/rendered at "/dashboard*"
      <Outlet /> // <-- conditionally matched/rendered children
    </>
  );
};

Nested-Routes

You may have noticed when clicking the links that the layout in App disappears. Repeating shared layouts is a pain in the neck. We've learned that most UI is a series of nested layouts that almost always map to segments of the URL so this idea is baked right in to React Router.

I believe what you are expecting is what is called an Index Route. It is what would be rendered on a "/dashboard" route when it isn't a layout/wrapper container.

Notice it has the index prop instead of a path. That's because the index route shares the path of the parent. That's the whole point--it doesn't have a path.

Maybe you're still scratching your head. There are a few ways we try to answer the question "what is an index route?". Hopefully one of these sticks for you:

  • Index routes render in the parent routes outlet at the parent route's path.
  • Index routes match when a parent route matches but none of the other children match.
  • Index routes are the default child route for a parent route.
  • Index routes render when the user hasn't clicked one of the items in a navigation list yet.
const AppRouter = () => {
  return (
    <div>
      <Navbar />
      <Routes>
        <Route path="/" element={<HomeView />} />
        <Route path="dashboard" element={<DashboardLayout />}>
          <Route path="employee" element={<EmployeeHomeView />} />
          <Route path="accounting" element={<AccountingHomeView />} />
          <Route index element={<DashboardHomeView />} />
        </Route>
        <Route path="/login" element={<LoginView />} />
      </Routes>
    </div>
  );
};

const DashboardLayout = function () {
  return (
    <div /* with any layout styling */>
      .... other common layout content
      <Outlet />
      .... more possible common page content
    </div>
  );
};

const DashboardHomeView = function () {
  return (
    <>
      <h1>DashboardHomeView</h1>
      .... dashboard specific content
    </>
  );
};

How about using the exact prop for the parent Route. Like <Route exact path="dashboard" element={<DashboardHomeView />}>. This may solve the issue.

Related