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

All we need is an easy explanation of the problem, so here it is.

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;

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

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
    </>
  );
};

Method 2

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

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply