0
votes

I have nested routes, the third level routes are failing. This is my routing structure yeah.... but the problem is, App.js Routes to -Home -About -Dashboard Then Dashboard has children component to -Profile (/dashboard/user) -Account (/dashboard/account) -Wallet (/dashboard/wallet) -Settings (/dashboard/settings) Then Settings has other children components -Edit Profile (/dashboard/settings/editprofile) -Edit Password and Pin (/dashboard/settings/editpassword) -Edit Account Number (/dashboard/settings/editnumber)

The top two level routes are working, but the last one fails when i refresh the page, although it renders when i go back to the homepage and click on the links till i get to the last component, but once i refresh my browser it breaks, also it doesn't work when i type it manually.

Here is my App.js Route setup

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Redirect,
} from "react-router-dom";

const App = () => {
  return (
    <div className="App">
      {/* setting up the routes */}
      <Router>
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/dashboard" component={dashboard} />
          <Route path="/login" exact component={Login} />
          <Route path="/register" exact component={SignUp} />
          <Route path="/about" exact component={AboutServices} />
        </Switch>
      </Router>
    </div>
  );
};

My DashBoard.js

import { Route, useRouteMatch, NavLink, Switch } from "react-router-dom";
const App = () => {
     let { path, url } = useRouteMatch();
  return (
    <div className="App">
       <nav> Navavigation bar <nav>

      {/* setting up the routes */}

    <div className="MainBody">
      <Switch>
        <Route path={`${path}/wallet`} exact component={Wallet} />
        <Route path={`${path}/profile`} component={Profile} />
        <Route path={`${path}/account`} component={Account} />
        <Route path={`${path}/settings`} exact component={Settings} />
      </Switch>
    </div> 
    </div>
  );
};

Settings Page

import {
  Switch,
  Route,
  useRouteMatch,
  NavLink,
  BrowserRouter,
} from "react-router-dom";

const Settings = (props) => {
  let { path, url } = useRouteMatch();

  return (
    <div className="Settings">
      <BrowserRouter>
          <nav> Navavigation bar <nav>
          <div className="SettingsWrapper">
            <Switch>
              <Route path={`${path}/editprofile`} component={EditProfile} />
              <Route
                path={`${path}/changepassword`}
                component={ChangePassword}
              />
              <Route path={`${path}/changepin`} component={ChangePin} />
              <Route
                path={`${path}/accountsettings`}
                component={BankSettings}
              />
            </Switch>
          </div>
        </div>
      </BrowserRouter>
    </div>
  );
};

export default Settings;
1

1 Answers

2
votes

I am 99% sure your issue is because you are using more than 1 router. Remove the BrowserRouter around your Settings UI. I am guessing when the nested routes aren't navigated to via links from the outer router that the match prop isn't initialized as you expect it to be.

const Settings = (props) => {
  let { path, url } = useRouteMatch();

  return (
    <div className="Settings">
      <nav>Navigation bar</nav>
      <div className="SettingsWrapper">
        <Switch>
          <Route path={`${path}/editprofile`} component={EditProfile} />
          <Route
            path={`${path}/changepassword`}
            component={ChangePassword}
          />
          <Route path={`${path}/changepin`} component={ChangePin} />
          <Route
            path={`${path}/accountsettings`}
            component={BankSettings}
          />
        </Switch>
      </div>
    </div>
  );
};

Edit

Ok, when removing the nested router and creating my own codesandbox I found a small, subtle but important "quirk" of nesting routes. Any nested route that is rendering further routes can not specify the exact prop on the route.

const App = () => {
     let { path, url } = useRouteMatch();
  return (
    <div className="App">
       <nav>Navigation bar</nav>

      {/* setting up the routes */}

      <div className="MainBody">
        <Switch>
          ...
          <Route
            path={`${path}/settings`}
            exact // <-- exact match precludes sub-routes!!
            component={Settings}
          />
        </Switch>
      </div> 
    </div>
  );
};

So if for example the path was "/dashboard/settings/editprofile" the path no longer exactly matches the route path and the route is not rendered.

Solution

Simply omit the exact prop for nested routes rendering sub-routes. Remember that route paths are to be considered "prefixes", so without the exact prop specified that path "/dashboard/settings/editprofile" can be matched by "/dashboard/settings".

const Dashboard = () => {
  let { path, url } = useRouteMatch();

  return (
    <div className="App">
      <nav>Dashboard Navigation bar </nav>
      <NavLink to={`${url}/settings`}>Settings</NavLink>

      {/* setting up the routes */}

      <div className="MainBody">
        <Switch>
          ...
          <Route path={`${path}/settings`} component={Settings} /> // <-- no exact match
        </Switch>
      </div>
    </div>
  );
};

Edit react-router-doesnt-show-component-when-i-refresh/64744387