SajZ
SajZ

Reputation: 260

React Router not working with multiple fragments

I want to implement side bar and wrap them in a div only for few routes. The other routes should not be having the sidebar.

all the pages from top was working except the * wildcard route. Console it says React does not recognize the computedMatch prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase computedmatch instead. If you accidentally passed it from a parent component, remove it from the DOM element.

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

import Header from "./components/header";

import LoginPage from "./pages/login";
import DashboardPage from "./pages/dashboard";
import NotfoundPage from "./pages/notfound";

export default function App() {
  return (
    <Router>
      <Header />
      <Switch>
        <Route exact path="/" component={LoginPage} />
        <main className="dashboardMain">
          <React.Fragment>
            <SideBar />
            <Route
              exact
              path="/dashboard"
              component={withRouter(DashboardPage)}
            />
          </React.Fragment>
        </main>
        <Route path="*" component={NotfoundPage} />
      </Switch>
    </Router>
  );
}

Upvotes: 0

Views: 1089

Answers (1)

lala
lala

Reputation: 1439

I once have stumbled the same issue. Maybe because we didn't suppose to have nested element in between Route (I'm not sure about this tho). Anyway, this is the fixes I did to my system:-

  • separate additional & conditional element in different component.
  • create a new component which gonna act as a parent OR wrapper for all our Switch & Route.
  • from there we can determine which Route should have sidebar & which don't.

For the following example, I use Context API which oversee whether user already login or not. Only loggedIn user will have access to sidebar. To make this work, We're gonna need to make some of our Route protected. See the implementation below:-

  • in App.js (We will import Nav as new external parent or wrapper component for all our Switch & Route. We only have Dashboard component be protected. Only accessible for loggedIn user):-
import React from "react";
import "./styles.css";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { AuthState } from "./contexts/AuthState";
import ProtectedRoute from "./comps/ProtectedRoute";
import Nav from "./comps/Nav";
import Login from "./comps/Login";

export default function App() {
  return (
    <AuthState>
      <Router>
        {/* Nav is an external parent component */}
        <Nav>
          <Switch>
            <Route exact path="/" component={() => "Home page!"} />
            <Route exact path="/about" component={() => "About page!"} />
            <Route exact path="/login" component={Login} />
            <ProtectedRoute
              path="/dashboard"
              component={() => "Dashboard page!"}
            />
            <Route path="*" component={() => "Not Found page!"} />
          </Switch>
        </Nav>
      </Router>
    </AuthState>
  );
}

  • in Nav (here we will receive children as props for Nav component - which are actually all our Switch & Route from App.js. In addition, we also do conditional statement here to only display sidebar for loggedIn user. Else, we'll just display the content (children we received) of the component that get rendered):-
import React, { useState, useEffect } from "react";
import { NavLink } from "react-router-dom";
import { useAuth } from "../contexts/AuthState";
import { logOut } from "../contexts/AuthAction";

const Nav = ({ children }) => {
  const [authState, authDispatch] = useAuth();
  const { auth } = authState;

  const [isLogout, setIsLogout] = useState(false);

  // handle logout
  useEffect(() => {
    (() => {
      if (isLogout) {
        logOut(authDispatch);

        // reset state
        setIsLogout(false);
      }
    })();
  }, [isLogout]);

  return (
    <>
      <ul
        style={{
          listStyle: "none",
          display: "flex",
          justifyContent: "center",
          alignItems: "center"
        }}
      >
        <li style={{ marginRight: 10 }}>
          <NavLink to="/">Home</NavLink>
        </li>
        <li style={{ marginRight: 10 }}>
          <NavLink to="/about">About</NavLink>
        </li>
        {!auth && (
          <li>
            <NavLink to="/login">Login</NavLink>
          </li>
        )}
      </ul>
      {/* condition happen here
      display sidebar for loggedin user
      else just display content (children) */}
      {auth ? (
        // display content with sidebar
        <div
          style={{
            display: "flex"
          }}
        >
          <ul
            style={{
              listStyle: "none",
              margin: 0,
              padding: 10,
              width: "20%",
              minHeight: "100vh",
              backgroundColor: "grey"
            }}
          >
            <li style={{ marginBottom: 10 }}>
              <NavLink to="/dashboard">Dashboard</NavLink>
            </li>
            <li>
              <button onClick={() => setIsLogout(true)}>Logout</button>
            </li>
          </ul>
          <div
            style={{
              padding: 10,
              width: "100%",
              backgroundColor: "lightyellow"
            }}
          >
            <h2 style={{ margin: "0 0 20px 0", padding: 0 }}>Content </h2>
            {children}
          </div>
        </div>
      ) : (
        // just display content without sidebar
        children
      )}
    </>
  );
};

export default Nav;

You can refer to this working sandbox of said example use above.

Upvotes: 1

Related Questions