How to create a protected route with react-router-dom?

How to create a protected route with react-router-dom and storing the response in localStorage, so that when a user tries to open next time they can view their details again. After login, they should redirect to the dashboard page.

All functionality is added in ContextApi.
Codesandbox link : Code

I tried but was not able to achieve it

Route Page

import React, { useContext } from "react";
import { globalC } from "./context";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import About from "./About";
import Dashboard from "./Dashboard";
import Login from "./Login";
import PageNotFound from "./PageNotFound";

function Routes() {
  const { authLogin } = useContext(globalC);
  console.log("authLogin", authLogin);

  return (
    <BrowserRouter>
      <Switch>
        {authLogin ? (
          <>
            <Route path="/dashboard" component={Dashboard} exact />
            <Route exact path="/About" component={About} />
          </>
        ) : (
          <Route path="/" component={Login} exact />
        )}

        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
  );
}
export default Routes;

Context Page

import React, { Component, createContext } from "react";
import axios from "axios";

export const globalC = createContext();

export class Gprov extends Component {
  state = {
    authLogin: null,
    authLoginerror: null
  };
  componentDidMount() {
    var localData = JSON.parse(localStorage.getItem("loginDetail"));
    if (localData) {
      this.setState({
        authLogin: localData
      });
    }
  }

  loginData = async () => {
    let payload = {
      token: "ctz43XoULrgv_0p1pvq7tA",
      data: {
        name: "nameFirst",
        email: "internetEmail",
        phone: "phoneHome",
        _repeat: 300
      }
    };
    await axios
      .post(`https://app.fakejson.com/q`, payload)
      .then((res) => {
        if (res.status === 200) {
          this.setState({
            authLogin: res.data
          });
          localStorage.setItem("loginDetail", JSON.stringify(res.data));
        }
      })
      .catch((err) =>
        this.setState({
          authLoginerror: err
        })
      );
  };
  render() {
    // console.log(localStorage.getItem("loginDetail"));
    return (
      <globalC.Provider
        value={{
          ...this.state,
          loginData: this.loginData
        }}
      >
        {this.props.children}
      </globalC.Provider>
    );
  }
}

0

Issue

<BrowserRouter>
  <Switch>
    {authLogin ? (
      <>
        <Route path="/dashboard" component={Dashboard} exact />
        <Route exact path="/About" component={About} />
      </>
    ) : (
      <Route path="/" component={Login} exact />
    )}

    <Route component={PageNotFound} />
  </Switch>
</BrowserRouter>

The Switch doesn’t handle rendering anything other than Route and Redirect components. If you want to “nest” like this then you need to wrap each in generic routes, but that is completely unnecessary.

Your login component also doesn’t handle redirecting back to any “home” page or private routes that were originally being accessed.

Solution

react-router-dom v6 and v7

In version 6/7 custom route components no longer work, the preferred method is to use an auth layout component.

import { Navigate, Outlet } from 'react-router-dom'; // Note 1

const PrivateRoutes = () => {
  const location = useLocation();
  const { authLogin } = useContext(globalC);

  if (authLogin === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  return authLogin 
    ? <Outlet />
    : <Navigate to="/login" replace state={{ from: location }} />;
}

<BrowserRouter>
  <Routes>
    <Route path="/" element={<PrivateRoutes />} >
      <Route path="dashboard" element={<Dashboard />} />
      <Route path="about" element={<About />} />
    </Route>
    <Route path="/login" element={<Login />} />
    <Route path="*" element={<PageNotFound />} />
  </Routes>
</BrowserRouter>

or

const routes = [
  {
    path: "/",
    element: <PrivateRoutes />,
    children: [
      {
        path: "dashboard",
        element: <Dashboard />,
      },
      {
        path: "about",
        element: <About />
      },
    ],
  },
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "*",
    element: <PageNotFound />
  },
];

export default function Login() {
  const location = useLocation();
  const navigate = useNavigate();
  const { authLogin, loginData } = useContext(globalC);

  useEffect(() => {
    if (authLogin) {
      const { from } = location.state || { from: { pathname: "/" } };
      navigate(from, { replace: true });
    }
  }, [authLogin, location, navigate]);

  return (
    <div
      style={{ height: "100vh" }}
      className="d-flex justify-content-center align-items-center"
    >
      <button type="button" onClick={loginData} className="btn btn-primary">
        Login
      </button>
    </div>
  );
}

1 React-Router-DOM v7 react-router is the primary entry point, import components from react-router instead of react-router-dom. See v7 Installation for details.

react-router-dom v5

Create a PrivateRoute component that consumes your auth context.

const PrivateRoute = (props) => {
  const location = useLocation();
  const { authLogin } = useContext(globalC);

  if (authLogin === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  return authLogin ? (
    <Route {...props} />
  ) : (
    <Redirect
      to={{
        pathname: "/login",
        state: { from: location }
      }}
    />
  );
};

Update your Login component to handle redirecting back to the original route being accessed.

export default function Login() {
  const location = useLocation();
  const history = useHistory();
  const { authLogin, loginData } = useContext(globalC);

  useEffect(() => {
    if (authLogin) {
      const { from } = location.state || { from: { pathname: "/" } };
      history.replace(from);
    }
  }, [authLogin, history, location]);

  return (
    <div
      style={{ height: "100vh" }}
      className="d-flex justify-content-center align-items-center"
    >
      <button type="button" onClick={loginData} className="btn btn-primary">
        Login
      </button>
    </div>
  );
}

Render all your routes in a “flat list”

function Routes() {
  return (
    <BrowserRouter>
      <Switch>
        <PrivateRoute path="/dashboard" component={Dashboard} />
        <PrivateRoute path="/About" component={About} />
        <Route path="/login" component={Login} />
        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
  );
}

8

For v6:

import { Routes, Route, Navigate } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="/public" element={<PublicPage />} />
      <Route
        path="/protected"
        element={
          <RequireAuth redirectTo="/login">
            <ProtectedPage />
          </RequireAuth>
        }
      />
    </Routes>
  );
}

function RequireAuth({ children, redirectTo }) {
  let isAuthenticated = getAuth();
  return isAuthenticated ? children : <Navigate to={redirectTo} />;
}

Link to docs:
https://gist.github.com/mjackson/d54b40a094277b7afdd6b81f51a0393f

3

This Answer for Newer of Reactjs

React Router Dom: ^ v6

//App.js
<Route path="/"
       element={<HomePage /> } />

<Route path="/dashboard"
       element={<AuthMiddleware> <DashboardPage /> </AuthMiddleware>}
/>
// AuthMiddelware.js
import { Navigate } from "react-router-dom"

export const AuthMiddleware = (props) => { 
    
    const token = true; // get login status here
    
    const { auth=token, children, redirect = '/login' } = props; 

    if (!auth) {
       return <Navigate to={redirect} replace />;
    }
    return children;
 };

0

If you want an easy way to implement then use Login in App.js, if user is loggedin then set user variable. If user variable is set then start those route else it will stuck at login page. I implemented this in my project.

  return (
    <div>
      <Notification notification={notification} type={notificationType} />

      {
        user === null &&
        <LoginForm startLogin={handleLogin} />
      }

      {
        user !== null &&
        <NavBar user={user} setUser={setUser} />
      }

      {
        user !== null &&
        <Router>
          <Routes>
            <Route exact path="/" element={<Home />} />
            <Route exact path="/adduser" element={<AddUser />} /> />
            <Route exact path="/viewuser/:id" element={<ViewUser />} />
          </Routes>
        </Router>
      }

    </div>
  )

import { BrowserRouter as Router } from "react-router-dom";        
import { Routes, Route } from "react-router-dom";      
import Home from "./component/home/Home.js";      
import Products from "./component/Products/Products.js";      
import Profile from "./component/user/Profile.js";      
      
import ProtectedRoute from "./component/Route/ProtectedRoute";      
function App() {      
 return (      
    <Router>      
    <Routes>      
        <Route path="/" element={<Home />} />      
        <Route path="/products" element={<Products />} />      
        <Route      
          path="/account"      
          element={      
            <ProtectedRoute  >      
              <Profile />      
            </ProtectedRoute>      
          }      
        />      
      </Routes>      
       </Router>      
  );      
}      
      
//ProtectedRoute       

export default App;      
import React from "react";      
import { useSelector } from "react-redux";      
import { Navigate } from "react-router-dom";      

function ProtectedRoute({ children }) {      
  const { isAuthecated, loading } = useSelector((state) => state.user);      
      
  if (!isAuthecated) {      
    return <Navigate to="/login" replace />;      
  }      
  return children;      
}      
export default ProtectedRoute;      
      

2

import { v4 as uuidv4 } from "uuid";

const routes = [
    {
        id: uuidv4(),
        isProtected: false,
        exact: true,
        path: "/home",
        component: param => <Overview {...param} />,
    },
    {
        id: uuidv4(),
        isProtected: true,
        exact: true,
        path: "/protected",
        component: param => <Overview {...param} />,
        allowed: [...advanceProducts], // subscription
    },
    {
        // if you conditional based rendering for same path
        id: uuidv4(),
        isProtected: true,
        exact: true,
        path: "/",
        component: null,
        conditionalComponent: true,
        allowed: {
            [subscription1]: param => <Overview {...param} />,
            [subscription2]: param => <Customers {...param} />,
        },
    },
]

// Navigation Component
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Switch, Route, useLocation } from "react-router-dom";

// ...component logic
<Switch>
    {routes.map(params => {
        return (
            <ProtectedRoutes
                exact
                routeParams={params}
                key={params.path}
                path={params.path}
            />
        );
    })}
    <Route
        render={() => {
            props.setHideNav(true);
            setHideHeader(true);
            return <ErrorPage type={404} />;
        }}
    />
</Switch>

// ProtectedRoute component
import React from "react";
import { Route } from "react-router-dom";
import { useSelector } from "react-redux";

const ProtectedRoutes = props => {
    const { routeParams } = props;
    const currentSubscription = 'xyz'; // your current subscription;
    if (routeParams.conditionalComponent) {
        return (
            <Route
                key={routeParams.path}
                path={routeParams.path}
                render={routeParams.allowed[currentSubscription]}
            />
        );
    }
    if (routeParams.isProtected && routeParams.allowed.includes(currentSubscription)) {
        return (
            <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
        );
    }
    if (!routeParams.isProtected) {
        return (
            <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
        );
    }
    return null;
};

export default ProtectedRoutes;

Would like to add highlight never forget to give path as prop to ProtectedRoute, else it will not work.

Here is an easy react-router v6 protected route. I have put all the routes I want to protect in a routes.js:-

const routes = [{ path: "/dasboard", name:"Dashboard", element: <Dashboard/> }]

To render the routes just map them as follows: –

<Routes>
   {routes.map((routes, id) => {
     return(
     <Route
         key={id}
         path={route.path}
         exact={route.exact}
         name={route.name}
         element={
            localStorage.getItem("token") ? (
                route.element
             ) : (
                <Navigate to="/login" />
             )
         }
     )
   })
  }
</Routes>

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

How to create a protected route with react-router-dom?

How to create a protected route with react-router-dom and storing the response in localStorage, so that when a user tries to open next time they can view their details again. After login, they should redirect to the dashboard page.

All functionality is added in ContextApi.
Codesandbox link : Code

I tried but was not able to achieve it

Route Page

import React, { useContext } from "react";
import { globalC } from "./context";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import About from "./About";
import Dashboard from "./Dashboard";
import Login from "./Login";
import PageNotFound from "./PageNotFound";

function Routes() {
  const { authLogin } = useContext(globalC);
  console.log("authLogin", authLogin);

  return (
    <BrowserRouter>
      <Switch>
        {authLogin ? (
          <>
            <Route path="/dashboard" component={Dashboard} exact />
            <Route exact path="/About" component={About} />
          </>
        ) : (
          <Route path="/" component={Login} exact />
        )}

        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
  );
}
export default Routes;

Context Page

import React, { Component, createContext } from "react";
import axios from "axios";

export const globalC = createContext();

export class Gprov extends Component {
  state = {
    authLogin: null,
    authLoginerror: null
  };
  componentDidMount() {
    var localData = JSON.parse(localStorage.getItem("loginDetail"));
    if (localData) {
      this.setState({
        authLogin: localData
      });
    }
  }

  loginData = async () => {
    let payload = {
      token: "ctz43XoULrgv_0p1pvq7tA",
      data: {
        name: "nameFirst",
        email: "internetEmail",
        phone: "phoneHome",
        _repeat: 300
      }
    };
    await axios
      .post(`https://app.fakejson.com/q`, payload)
      .then((res) => {
        if (res.status === 200) {
          this.setState({
            authLogin: res.data
          });
          localStorage.setItem("loginDetail", JSON.stringify(res.data));
        }
      })
      .catch((err) =>
        this.setState({
          authLoginerror: err
        })
      );
  };
  render() {
    // console.log(localStorage.getItem("loginDetail"));
    return (
      <globalC.Provider
        value={{
          ...this.state,
          loginData: this.loginData
        }}
      >
        {this.props.children}
      </globalC.Provider>
    );
  }
}

0

Issue

<BrowserRouter>
  <Switch>
    {authLogin ? (
      <>
        <Route path="/dashboard" component={Dashboard} exact />
        <Route exact path="/About" component={About} />
      </>
    ) : (
      <Route path="/" component={Login} exact />
    )}

    <Route component={PageNotFound} />
  </Switch>
</BrowserRouter>

The Switch doesn’t handle rendering anything other than Route and Redirect components. If you want to “nest” like this then you need to wrap each in generic routes, but that is completely unnecessary.

Your login component also doesn’t handle redirecting back to any “home” page or private routes that were originally being accessed.

Solution

react-router-dom v6 and v7

In version 6/7 custom route components no longer work, the preferred method is to use an auth layout component.

import { Navigate, Outlet } from 'react-router-dom'; // Note 1

const PrivateRoutes = () => {
  const location = useLocation();
  const { authLogin } = useContext(globalC);

  if (authLogin === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  return authLogin 
    ? <Outlet />
    : <Navigate to="/login" replace state={{ from: location }} />;
}

<BrowserRouter>
  <Routes>
    <Route path="/" element={<PrivateRoutes />} >
      <Route path="dashboard" element={<Dashboard />} />
      <Route path="about" element={<About />} />
    </Route>
    <Route path="/login" element={<Login />} />
    <Route path="*" element={<PageNotFound />} />
  </Routes>
</BrowserRouter>

or

const routes = [
  {
    path: "/",
    element: <PrivateRoutes />,
    children: [
      {
        path: "dashboard",
        element: <Dashboard />,
      },
      {
        path: "about",
        element: <About />
      },
    ],
  },
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "*",
    element: <PageNotFound />
  },
];

export default function Login() {
  const location = useLocation();
  const navigate = useNavigate();
  const { authLogin, loginData } = useContext(globalC);

  useEffect(() => {
    if (authLogin) {
      const { from } = location.state || { from: { pathname: "/" } };
      navigate(from, { replace: true });
    }
  }, [authLogin, location, navigate]);

  return (
    <div
      style={{ height: "100vh" }}
      className="d-flex justify-content-center align-items-center"
    >
      <button type="button" onClick={loginData} className="btn btn-primary">
        Login
      </button>
    </div>
  );
}

1 React-Router-DOM v7 react-router is the primary entry point, import components from react-router instead of react-router-dom. See v7 Installation for details.

react-router-dom v5

Create a PrivateRoute component that consumes your auth context.

const PrivateRoute = (props) => {
  const location = useLocation();
  const { authLogin } = useContext(globalC);

  if (authLogin === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  return authLogin ? (
    <Route {...props} />
  ) : (
    <Redirect
      to={{
        pathname: "/login",
        state: { from: location }
      }}
    />
  );
};

Update your Login component to handle redirecting back to the original route being accessed.

export default function Login() {
  const location = useLocation();
  const history = useHistory();
  const { authLogin, loginData } = useContext(globalC);

  useEffect(() => {
    if (authLogin) {
      const { from } = location.state || { from: { pathname: "/" } };
      history.replace(from);
    }
  }, [authLogin, history, location]);

  return (
    <div
      style={{ height: "100vh" }}
      className="d-flex justify-content-center align-items-center"
    >
      <button type="button" onClick={loginData} className="btn btn-primary">
        Login
      </button>
    </div>
  );
}

Render all your routes in a “flat list”

function Routes() {
  return (
    <BrowserRouter>
      <Switch>
        <PrivateRoute path="/dashboard" component={Dashboard} />
        <PrivateRoute path="/About" component={About} />
        <Route path="/login" component={Login} />
        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
  );
}

8

For v6:

import { Routes, Route, Navigate } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="/public" element={<PublicPage />} />
      <Route
        path="/protected"
        element={
          <RequireAuth redirectTo="/login">
            <ProtectedPage />
          </RequireAuth>
        }
      />
    </Routes>
  );
}

function RequireAuth({ children, redirectTo }) {
  let isAuthenticated = getAuth();
  return isAuthenticated ? children : <Navigate to={redirectTo} />;
}

Link to docs:
https://gist.github.com/mjackson/d54b40a094277b7afdd6b81f51a0393f

3

This Answer for Newer of Reactjs

React Router Dom: ^ v6

//App.js
<Route path="/"
       element={<HomePage /> } />

<Route path="/dashboard"
       element={<AuthMiddleware> <DashboardPage /> </AuthMiddleware>}
/>
// AuthMiddelware.js
import { Navigate } from "react-router-dom"

export const AuthMiddleware = (props) => { 
    
    const token = true; // get login status here
    
    const { auth=token, children, redirect = '/login' } = props; 

    if (!auth) {
       return <Navigate to={redirect} replace />;
    }
    return children;
 };

0

If you want an easy way to implement then use Login in App.js, if user is loggedin then set user variable. If user variable is set then start those route else it will stuck at login page. I implemented this in my project.

  return (
    <div>
      <Notification notification={notification} type={notificationType} />

      {
        user === null &&
        <LoginForm startLogin={handleLogin} />
      }

      {
        user !== null &&
        <NavBar user={user} setUser={setUser} />
      }

      {
        user !== null &&
        <Router>
          <Routes>
            <Route exact path="/" element={<Home />} />
            <Route exact path="/adduser" element={<AddUser />} /> />
            <Route exact path="/viewuser/:id" element={<ViewUser />} />
          </Routes>
        </Router>
      }

    </div>
  )

import { BrowserRouter as Router } from "react-router-dom";        
import { Routes, Route } from "react-router-dom";      
import Home from "./component/home/Home.js";      
import Products from "./component/Products/Products.js";      
import Profile from "./component/user/Profile.js";      
      
import ProtectedRoute from "./component/Route/ProtectedRoute";      
function App() {      
 return (      
    <Router>      
    <Routes>      
        <Route path="/" element={<Home />} />      
        <Route path="/products" element={<Products />} />      
        <Route      
          path="/account"      
          element={      
            <ProtectedRoute  >      
              <Profile />      
            </ProtectedRoute>      
          }      
        />      
      </Routes>      
       </Router>      
  );      
}      
      
//ProtectedRoute       

export default App;      
import React from "react";      
import { useSelector } from "react-redux";      
import { Navigate } from "react-router-dom";      

function ProtectedRoute({ children }) {      
  const { isAuthecated, loading } = useSelector((state) => state.user);      
      
  if (!isAuthecated) {      
    return <Navigate to="/login" replace />;      
  }      
  return children;      
}      
export default ProtectedRoute;      
      

2

import { v4 as uuidv4 } from "uuid";

const routes = [
    {
        id: uuidv4(),
        isProtected: false,
        exact: true,
        path: "/home",
        component: param => <Overview {...param} />,
    },
    {
        id: uuidv4(),
        isProtected: true,
        exact: true,
        path: "/protected",
        component: param => <Overview {...param} />,
        allowed: [...advanceProducts], // subscription
    },
    {
        // if you conditional based rendering for same path
        id: uuidv4(),
        isProtected: true,
        exact: true,
        path: "/",
        component: null,
        conditionalComponent: true,
        allowed: {
            [subscription1]: param => <Overview {...param} />,
            [subscription2]: param => <Customers {...param} />,
        },
    },
]

// Navigation Component
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Switch, Route, useLocation } from "react-router-dom";

// ...component logic
<Switch>
    {routes.map(params => {
        return (
            <ProtectedRoutes
                exact
                routeParams={params}
                key={params.path}
                path={params.path}
            />
        );
    })}
    <Route
        render={() => {
            props.setHideNav(true);
            setHideHeader(true);
            return <ErrorPage type={404} />;
        }}
    />
</Switch>

// ProtectedRoute component
import React from "react";
import { Route } from "react-router-dom";
import { useSelector } from "react-redux";

const ProtectedRoutes = props => {
    const { routeParams } = props;
    const currentSubscription = 'xyz'; // your current subscription;
    if (routeParams.conditionalComponent) {
        return (
            <Route
                key={routeParams.path}
                path={routeParams.path}
                render={routeParams.allowed[currentSubscription]}
            />
        );
    }
    if (routeParams.isProtected && routeParams.allowed.includes(currentSubscription)) {
        return (
            <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
        );
    }
    if (!routeParams.isProtected) {
        return (
            <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
        );
    }
    return null;
};

export default ProtectedRoutes;

Would like to add highlight never forget to give path as prop to ProtectedRoute, else it will not work.

Here is an easy react-router v6 protected route. I have put all the routes I want to protect in a routes.js:-

const routes = [{ path: "/dasboard", name:"Dashboard", element: <Dashboard/> }]

To render the routes just map them as follows: –

<Routes>
   {routes.map((routes, id) => {
     return(
     <Route
         key={id}
         path={route.path}
         exact={route.exact}
         name={route.name}
         element={
            localStorage.getItem("token") ? (
                route.element
             ) : (
                <Navigate to="/login" />
             )
         }
     )
   })
  }
</Routes>

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

How to create a protected route with react-router-dom?

How to create a protected route with react-router-dom and storing the response in localStorage, so that when a user tries to open next time they can view their details again. After login, they should redirect to the dashboard page.

All functionality is added in ContextApi.
Codesandbox link : Code

I tried but was not able to achieve it

Route Page

import React, { useContext } from "react";
import { globalC } from "./context";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import About from "./About";
import Dashboard from "./Dashboard";
import Login from "./Login";
import PageNotFound from "./PageNotFound";

function Routes() {
  const { authLogin } = useContext(globalC);
  console.log("authLogin", authLogin);

  return (
    <BrowserRouter>
      <Switch>
        {authLogin ? (
          <>
            <Route path="/dashboard" component={Dashboard} exact />
            <Route exact path="/About" component={About} />
          </>
        ) : (
          <Route path="/" component={Login} exact />
        )}

        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
  );
}
export default Routes;

Context Page

import React, { Component, createContext } from "react";
import axios from "axios";

export const globalC = createContext();

export class Gprov extends Component {
  state = {
    authLogin: null,
    authLoginerror: null
  };
  componentDidMount() {
    var localData = JSON.parse(localStorage.getItem("loginDetail"));
    if (localData) {
      this.setState({
        authLogin: localData
      });
    }
  }

  loginData = async () => {
    let payload = {
      token: "ctz43XoULrgv_0p1pvq7tA",
      data: {
        name: "nameFirst",
        email: "internetEmail",
        phone: "phoneHome",
        _repeat: 300
      }
    };
    await axios
      .post(`https://app.fakejson.com/q`, payload)
      .then((res) => {
        if (res.status === 200) {
          this.setState({
            authLogin: res.data
          });
          localStorage.setItem("loginDetail", JSON.stringify(res.data));
        }
      })
      .catch((err) =>
        this.setState({
          authLoginerror: err
        })
      );
  };
  render() {
    // console.log(localStorage.getItem("loginDetail"));
    return (
      <globalC.Provider
        value={{
          ...this.state,
          loginData: this.loginData
        }}
      >
        {this.props.children}
      </globalC.Provider>
    );
  }
}

0

Issue

<BrowserRouter>
  <Switch>
    {authLogin ? (
      <>
        <Route path="/dashboard" component={Dashboard} exact />
        <Route exact path="/About" component={About} />
      </>
    ) : (
      <Route path="/" component={Login} exact />
    )}

    <Route component={PageNotFound} />
  </Switch>
</BrowserRouter>

The Switch doesn’t handle rendering anything other than Route and Redirect components. If you want to “nest” like this then you need to wrap each in generic routes, but that is completely unnecessary.

Your login component also doesn’t handle redirecting back to any “home” page or private routes that were originally being accessed.

Solution

react-router-dom v6 and v7

In version 6/7 custom route components no longer work, the preferred method is to use an auth layout component.

import { Navigate, Outlet } from 'react-router-dom'; // Note 1

const PrivateRoutes = () => {
  const location = useLocation();
  const { authLogin } = useContext(globalC);

  if (authLogin === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  return authLogin 
    ? <Outlet />
    : <Navigate to="/login" replace state={{ from: location }} />;
}

<BrowserRouter>
  <Routes>
    <Route path="/" element={<PrivateRoutes />} >
      <Route path="dashboard" element={<Dashboard />} />
      <Route path="about" element={<About />} />
    </Route>
    <Route path="/login" element={<Login />} />
    <Route path="*" element={<PageNotFound />} />
  </Routes>
</BrowserRouter>

or

const routes = [
  {
    path: "/",
    element: <PrivateRoutes />,
    children: [
      {
        path: "dashboard",
        element: <Dashboard />,
      },
      {
        path: "about",
        element: <About />
      },
    ],
  },
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "*",
    element: <PageNotFound />
  },
];

export default function Login() {
  const location = useLocation();
  const navigate = useNavigate();
  const { authLogin, loginData } = useContext(globalC);

  useEffect(() => {
    if (authLogin) {
      const { from } = location.state || { from: { pathname: "/" } };
      navigate(from, { replace: true });
    }
  }, [authLogin, location, navigate]);

  return (
    <div
      style={{ height: "100vh" }}
      className="d-flex justify-content-center align-items-center"
    >
      <button type="button" onClick={loginData} className="btn btn-primary">
        Login
      </button>
    </div>
  );
}

1 React-Router-DOM v7 react-router is the primary entry point, import components from react-router instead of react-router-dom. See v7 Installation for details.

react-router-dom v5

Create a PrivateRoute component that consumes your auth context.

const PrivateRoute = (props) => {
  const location = useLocation();
  const { authLogin } = useContext(globalC);

  if (authLogin === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  return authLogin ? (
    <Route {...props} />
  ) : (
    <Redirect
      to={{
        pathname: "/login",
        state: { from: location }
      }}
    />
  );
};

Update your Login component to handle redirecting back to the original route being accessed.

export default function Login() {
  const location = useLocation();
  const history = useHistory();
  const { authLogin, loginData } = useContext(globalC);

  useEffect(() => {
    if (authLogin) {
      const { from } = location.state || { from: { pathname: "/" } };
      history.replace(from);
    }
  }, [authLogin, history, location]);

  return (
    <div
      style={{ height: "100vh" }}
      className="d-flex justify-content-center align-items-center"
    >
      <button type="button" onClick={loginData} className="btn btn-primary">
        Login
      </button>
    </div>
  );
}

Render all your routes in a “flat list”

function Routes() {
  return (
    <BrowserRouter>
      <Switch>
        <PrivateRoute path="/dashboard" component={Dashboard} />
        <PrivateRoute path="/About" component={About} />
        <Route path="/login" component={Login} />
        <Route component={PageNotFound} />
      </Switch>
    </BrowserRouter>
  );
}

8

For v6:

import { Routes, Route, Navigate } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="/public" element={<PublicPage />} />
      <Route
        path="/protected"
        element={
          <RequireAuth redirectTo="/login">
            <ProtectedPage />
          </RequireAuth>
        }
      />
    </Routes>
  );
}

function RequireAuth({ children, redirectTo }) {
  let isAuthenticated = getAuth();
  return isAuthenticated ? children : <Navigate to={redirectTo} />;
}

Link to docs:
https://gist.github.com/mjackson/d54b40a094277b7afdd6b81f51a0393f

3

This Answer for Newer of Reactjs

React Router Dom: ^ v6

//App.js
<Route path="/"
       element={<HomePage /> } />

<Route path="/dashboard"
       element={<AuthMiddleware> <DashboardPage /> </AuthMiddleware>}
/>
// AuthMiddelware.js
import { Navigate } from "react-router-dom"

export const AuthMiddleware = (props) => { 
    
    const token = true; // get login status here
    
    const { auth=token, children, redirect = '/login' } = props; 

    if (!auth) {
       return <Navigate to={redirect} replace />;
    }
    return children;
 };

0

If you want an easy way to implement then use Login in App.js, if user is loggedin then set user variable. If user variable is set then start those route else it will stuck at login page. I implemented this in my project.

  return (
    <div>
      <Notification notification={notification} type={notificationType} />

      {
        user === null &&
        <LoginForm startLogin={handleLogin} />
      }

      {
        user !== null &&
        <NavBar user={user} setUser={setUser} />
      }

      {
        user !== null &&
        <Router>
          <Routes>
            <Route exact path="/" element={<Home />} />
            <Route exact path="/adduser" element={<AddUser />} /> />
            <Route exact path="/viewuser/:id" element={<ViewUser />} />
          </Routes>
        </Router>
      }

    </div>
  )

import { BrowserRouter as Router } from "react-router-dom";        
import { Routes, Route } from "react-router-dom";      
import Home from "./component/home/Home.js";      
import Products from "./component/Products/Products.js";      
import Profile from "./component/user/Profile.js";      
      
import ProtectedRoute from "./component/Route/ProtectedRoute";      
function App() {      
 return (      
    <Router>      
    <Routes>      
        <Route path="/" element={<Home />} />      
        <Route path="/products" element={<Products />} />      
        <Route      
          path="/account"      
          element={      
            <ProtectedRoute  >      
              <Profile />      
            </ProtectedRoute>      
          }      
        />      
      </Routes>      
       </Router>      
  );      
}      
      
//ProtectedRoute       

export default App;      
import React from "react";      
import { useSelector } from "react-redux";      
import { Navigate } from "react-router-dom";      

function ProtectedRoute({ children }) {      
  const { isAuthecated, loading } = useSelector((state) => state.user);      
      
  if (!isAuthecated) {      
    return <Navigate to="/login" replace />;      
  }      
  return children;      
}      
export default ProtectedRoute;      
      

2

import { v4 as uuidv4 } from "uuid";

const routes = [
    {
        id: uuidv4(),
        isProtected: false,
        exact: true,
        path: "/home",
        component: param => <Overview {...param} />,
    },
    {
        id: uuidv4(),
        isProtected: true,
        exact: true,
        path: "/protected",
        component: param => <Overview {...param} />,
        allowed: [...advanceProducts], // subscription
    },
    {
        // if you conditional based rendering for same path
        id: uuidv4(),
        isProtected: true,
        exact: true,
        path: "/",
        component: null,
        conditionalComponent: true,
        allowed: {
            [subscription1]: param => <Overview {...param} />,
            [subscription2]: param => <Customers {...param} />,
        },
    },
]

// Navigation Component
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Switch, Route, useLocation } from "react-router-dom";

// ...component logic
<Switch>
    {routes.map(params => {
        return (
            <ProtectedRoutes
                exact
                routeParams={params}
                key={params.path}
                path={params.path}
            />
        );
    })}
    <Route
        render={() => {
            props.setHideNav(true);
            setHideHeader(true);
            return <ErrorPage type={404} />;
        }}
    />
</Switch>

// ProtectedRoute component
import React from "react";
import { Route } from "react-router-dom";
import { useSelector } from "react-redux";

const ProtectedRoutes = props => {
    const { routeParams } = props;
    const currentSubscription = 'xyz'; // your current subscription;
    if (routeParams.conditionalComponent) {
        return (
            <Route
                key={routeParams.path}
                path={routeParams.path}
                render={routeParams.allowed[currentSubscription]}
            />
        );
    }
    if (routeParams.isProtected && routeParams.allowed.includes(currentSubscription)) {
        return (
            <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
        );
    }
    if (!routeParams.isProtected) {
        return (
            <Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
        );
    }
    return null;
};

export default ProtectedRoutes;

Would like to add highlight never forget to give path as prop to ProtectedRoute, else it will not work.

Here is an easy react-router v6 protected route. I have put all the routes I want to protect in a routes.js:-

const routes = [{ path: "/dasboard", name:"Dashboard", element: <Dashboard/> }]

To render the routes just map them as follows: –

<Routes>
   {routes.map((routes, id) => {
     return(
     <Route
         key={id}
         path={route.path}
         exact={route.exact}
         name={route.name}
         element={
            localStorage.getItem("token") ? (
                route.element
             ) : (
                <Navigate to="/login" />
             )
         }
     )
   })
  }
</Routes>

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật