2

I'm trying to implement public and private routes in my project. the the uncommented section which has the private route works perfectly fine it denies the user from going to main page if it's not authenticated . Now I'm trying to configure the public routes which is the commented section which job will be to deny the user to go to the login page or register if he is logged in but it's not working it redirects me to /main page even if he is not authentiacted and doesn't go to login or register page.. although I read a lot of articles about this topic but it's not working with me ...Can you please explain briefly what is the problem exactly ?? I'm using router v5 You can see the code below

import React from "react";
import { Route, Redirect } from "react-router-dom";

const PrivateRoute = ({ component: Component, ...props }) => {
  const token = localStorage.getItem("isLogged");

  return (
    <Route
      {...props}
      render={(props) =>
        token ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{
              pathname: "/login",
            }}
          />
        )
      }
    />
  );
};

export default PrivateRoute;

The Public Route :

import React from "react";
import { Route, Redirect } from "react-router-dom";

const PublicRoute = ({ component: Component, ...props }) => {
  
  const token = localStorage.getItem("isLogged");

  return (
    <Route
      {...props}
      render={(props) =>
        token ? (
          <Redirect to={{ pathname: "/main" }} />
        ) : (
          <Component {...props} />
        )
      }
    ></Route>
  );
};

export default PublicRoute;

The App.js :

import "./App.css";
import Login from "./Components/Login";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Main from "./Pages/Main";
import Home from "./Pages/Home";
import Register from "./Components/Register";
import PrivateRoute from "./routes/PrivateRoute";
import PublicRoute from "./routes/PublicRoute";

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

      <Switch>
        <Route path="/" exact component={Home}></Route>
        <Route path="/login" component={Login}></Route>
        <Route path="/register" component={Register}></Route>
        <PrivateRoute component={Main}></PrivateRoute>
      </Switch>
      {/* <Switch>
        <Route path="/" exact component={Home}></Route>
        <PublicRoute path="/login" component={Login} exact></PublicRoute>
        <PublicRoute path="/register" component={Register} exact />
        <PrivateRoute path="/main" component={Main} exact></PrivateRoute>
      </Switch> */}
    </Router>
  );
}

export default App;
Nagween Jaffer
  • 180
  • 3
  • 13

1 Answers1

0

Issues

  1. The values fetched from localStorage will very likely be stringified values, i.e. JSON, so the token value is likely also a truthy value.
  2. The token value is only checked once when the custom route components mount instead of each time the route is accessed.

Solution

  1. Use JSON.parse to decode/parse the stored values from localStorage.

    const token = JSON.parse(localStorage.getItem("isLogged"));
    

    Ensure that any values you are saving into localStorage are also consistently stringified JSON.

    localStorage.setItem("isLogged", JSON.stringify(true));
    
  2. Either move the token access/check into to the render function

    const PrivateRoute = ({ component: Component, ...props }) => {
      return (
        <Route
          {...props}
          render={(props) =>{
            const token = JSON.parse(localStorage.getItem("isLogged"));
            return token ? (
              <Component {...props} />
            ) : (
              <Redirect
                to={{
                  pathname: "/login"
                }}
              />
            )}
          }
        />
      );
    };
    
    const PublicRoute = ({ component: Component, ...props }) => {
      return (
        <Route
          {...props}
          render={(props) =>{
            const token = JSON.parse(localStorage.getItem("isLogged"));
            return token ? (
              <Redirect to={{ pathname: "/main" }} />
            ) : (
              <Component {...props} />
            )}
          }
        ></Route>
      );
    };
    

    OR simplify your custom route components.

    const PrivateRoute = (props) => {
      const token = JSON.parse(localStorage.getItem("isLogged"));
      return token ? (
        <Route {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login"
          }}
        />
      );
    };
    
    const PublicRoute = (props) => {
      const token = JSON.parse(localStorage.getItem("isLogged"));
    
      return token ? (
        <Redirect to={{ pathname: "/main" }} />
      ) : (
        <Route {...props} />
      );
    };
    

Edit public-and-private-routes-in-react-using-local-storage

Drew Reese
  • 165,259
  • 14
  • 153
  • 181