EN VI

Reactjs - Is there a way to solve the combination between routes that affect each other?

2024-03-11 13:00:06
Reactjs - Is there a way to solve the combination between routes that affect each other?

I have Global file which holds the following routes:

global.tsx

import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import LoginPage from "../../pages/Authentication/Login";
import SignupPage from "../../pages/Authentication/Signup";

const Global = () => {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<LoginPage />} />
        <Route path="/signup" element={<SignupPage />}></Route>
      </Routes>
    </Router>
  );
};

export default Global;

and another file called Admin which holds these routes:

import React, { useContext, useEffect } from "react";
import "../../styles/App.scss";
import { ThemeContext } from "../../context/ThemeContext";
import { DARK_THEME, LIGHT_THEME } from "../../constants/themeConstants";
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import MoonIcon from '../../assets/icons/moon.svg';
import SunIcon from '../../assets/icons/sun.svg';
import BaseLayout from "../../layout/BaseLayout";
import DashboardScreen from "../../screens/Dashboard/DashboardScreen";
import PageNotFound from "../../screens/error/PageNotFound";

const Admin = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);

  console.log(theme);

  useEffect(() => {
    if (theme === DARK_THEME) {
      document.body.classList.add("dark-mode");
    } else {
      document.body.classList.remove("dark-mode");
    }
  }, [theme]);

  return (
    <>
    <Router>
      <Routes>
        <Route element={<BaseLayout />}>
          <Route path="/admin" element={<DashboardScreen />}></Route>
          <Route path="*" element={<PageNotFound />}></Route>
        </Route>
      </Routes>
      <button
        type="button" 
        className="theme-toggle-btn"
        onClick={toggleTheme}
      >
        <img
          src={theme === LIGHT_THEME ? SunIcon: MoonIcon}
          alt=""
          className="theme-icon"
        />
      </button>
    </Router>
    </>
  );
};

export default Admin;

and then combined them in one file:

// import "./App.scss";
import { SidebarProvider } from "./context/SidebarContext";
import { ThemeProvider } from "./context/ThemeContext";

import Admin from "./routes/admin/Admin";
import Global from "./routes/global/Global";

function App() {
  return (
    <div className="App">
      <Global />

      <ThemeProvider>
        <SidebarProvider>
          <Admin></Admin>
        </SidebarProvider>
      </ThemeProvider>
    </div>
  );
}

export default App;

what happens that is that the sidebar from the admin Router comes up with the login or sign up pages from Global component although the sidebar is from admin file in a different router as you can see in the following image:

enter image description here

I tried a lot of times with different ways to seperate them by playing with the routes but I couldn't. There has to be a way so that the sidebar don't come up with the the routes although the sidebar itself is a different route

Solution:

The two routers are rendered at the same time and so also render any matched routes at the same time.

You only need one router per React application. Refactor the code so App renders the single necessary Router component, and all routes rendered under a single Routes component that handles route matching. Descendent route paths are built relative to their parent route component.

Example:

Update Admin to be a layout route component that renders an Outlet for its nested routes.

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

const Admin = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);

  console.log(theme);

  useEffect(() => {
    if (theme === DARK_THEME) {
      document.body.classList.add("dark-mode");
    } else {
      document.body.classList.remove("dark-mode");
    }
  }, [theme]);

  return (
    <>
      <Outlet />
      <button
        type="button" 
        className="theme-toggle-btn"
        onClick={toggleTheme}
      >
        <img
          src={theme === LIGHT_THEME ? SunIcon : MoonIcon}
          alt=""
          className="theme-icon"
        />
      </button>
    </>
  );
};
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<LoginPage />} />
          <Route path="/signup" element={<SignupPage />} />
          <Route
            element={(
              <ThemeProvider>
                <SidebarProvider>
                  <Admin />
                </SidebarProvider>
               </ThemeProvider>
            )}
          >
            <Route element={<BaseLayout />}>
              <Route path="/admin" element={<DashboardScreen />} />
              <Route path="*" element={<PageNotFound />} />
            </Route>
          </Route>
        </Routes>
      </BrowserRouter>
    </div>
  );
}

Code Splitting

You could create functions that return JSX

Example:

import React from "react";
import { Route } from "react-router-dom";
import LoginPage from "../../pages/Authentication/Login";
import SignupPage from "../../pages/Authentication/Signup";

const globalRoutes = () => (
  <>
    <Route path="/" element={<LoginPage />} />
    <Route path="/signup" element={<SignupPage />} />
  </>
);

export default Global;
const adminRoutes = () => (
  <Route
    element={(
      <ThemeProvider>
        <SidebarProvider>
          <Admin />
        </SidebarProvider>
      </ThemeProvider>
    )}
  >
    <Route element={<BaseLayout />}>
      <Route path="/admin" element={<DashboardScreen />} />
      <Route path="*" element={<PageNotFound />} />
    </Route>
  </Route>
);
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          {globalRoutes()}
          {adminRoutes()}
        </Routes>
      </BrowserRouter>
    </div>
  );
}

It would be better to render the root-level routes directly where each routed component renders descendent routes (Routed components that render another Routes component and set of routes) instead. Basically each route is a sort of "namespace".

Example:

import React from "react";
import { Route, Routes } from "react-router-dom";
import LoginPage from "../../pages/Authentication/Login";
import SignupPage from "../../pages/Authentication/Signup";

const Global = () => {
  return (
    <Routes>
      <Route path="/" element={<LoginPage />} />
      <Route path="/signup" element={<SignupPage />} />
    </Routes>
  );
};

export default Global;
const Admin = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);

  console.log(theme);

  useEffect(() => {
    if (theme === DARK_THEME) {
      document.body.classList.add("dark-mode");
    } else {
      document.body.classList.remove("dark-mode");
    }
  }, [theme]);

  return (
    <>
      <Routes>
        <Route element={<BaseLayout />}>
          <Route path="/" element={<DashboardScreen />} /> // <-- "/admin"
          <Route path="*" element={<PageNotFound />} />
        </Route>
      </Routes>
      <button
        type="button" 
        className="theme-toggle-btn"
        onClick={toggleTheme}
      >
        <img
          src={theme === LIGHT_THEME ? SunIcon: MoonIcon}
          alt=""
          className="theme-icon"
        />
      </button>
    </>
  );
};
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route path="/*" element={<Global />} />
          <Route
            path="/admin/*"
            element={(
              <ThemeProvider>
                <SidebarProvider>
                  <Admin />
                </SidebarProvider>
              </ThemeProvider>
            )}
          />
        </Routes>
      </BrowserRouter>
    </div>
  );
}
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login