React, implementing protected route with authentication with React Router Dom

Viewed 366

Unable to route to admin page even after successful login, displays a blank screen. On successful login system should navigate and display the admin screen. Could someone please advise why the routing is not happening ?

//login.js

import React, { useEffect, useState } from 'react';
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";

const Login = () =>{
    const { register, errors, handleSubmit } = useForm();
    const [loginData, setLoginData] = useState("");
    const [helperText, setHelperText] = useState('');
    const navigate = useNavigate();

    const onSubmit = (data) => {
        try {
            const userEmail = "dev@test.com"; // for time being just hard code data
            const userPassword = "somePass123";  // for time being just hard code data
            if(data.email === userEmail && data.password === userPassword ){
                localStorage.setItem('loginEmail', userEmail);
                setLoginData(userEmail);
                navigate('/admin');
                window.location.reload(true) 
            } else {
                setHelperText("Invalid login details");
            }
        } catch (e){
            console.log(e);
        }
      };
    console.log(errors);

    return (
        <div className="wrapper">
            <h3>Login</h3>
            <section className="col2">
                <div className='loginSection'>
                    <form onSubmit={handleSubmit(onSubmit)}>
                        <label>Email</label>
                        <input
                            type="text"
                            {...register("email", { required: true})}
                        />
                        <label>Password</label>
                        <input
                            type="text"
                            {...register("password", { required: true})}
                        />
                         <label>
                            <span className="loginValidationText">{helperText}</span>
                         </label>
                        <section className="col4">
                        <input type="submit" />
                        </section>  
                    </form>
                </div>
            </section>
        </div>
    )
}
export default Login

//protectedRoute.js

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

export const ProtectedRoute = ({ component: Component, ...rest }) => {
  return (
    <Route
      {...rest}
      render={(props) => {
        if (localStorage.getItem("loginEmail")) {
          return <Component {...props} />;
        } else {
          return (
            <>
              <BrowserRouter
                to={{
                  pathname: "/login",
                  state: {
                    from: props.location,
                  },
                }}
              />
            </>
          );
        }
      }}
    />
  );
};

//navigation.js

import React from 'react';
import { NavLink} from 'react-router-dom';

const Navigation = () => {

    return (
        <div className="App">     
            <div className="wrapper">
                <div id="wrap">
                    <nav className="siteNavigation_nav_links">
                        <div className="main_links_nav">
                        <img className='logoimage' alt="SSS Logo" src="/images/super.png"></img>
                           <div className="navigationpanel">
                                <NavLink className="mob_link" to="/">Home</NavLink>
                                <NavLink className="mob_link" to="/team">Team</NavLink>
                                <NavLink className="mob_link" to="/login">Login</NavLink>
                           </div>
                        </div>
                    </nav>
                </div>
            </div>
        </div>
    )
}

export default Navigation;

//App.js

import React, { useEffect, useState } from 'react';
import { BrowserRouter, Route, Routes, Switch} from "react-router-dom";
import Navigation from './components/navigation';
import Home from "./components/home";
import Team from "./components/team";
import Admin from "./components/admin";
import Login from "./components/login";
import { ProtectedRoute } from "./components/protectedRoute";

function App() {
  return (
    <BrowserRouter>
    <Navigation />
        <Routes>
          <Route path="/"  element={<Home />}>
          </Route>
          <Route path="/team" element={<Team />}>
          </Route>
          <Route path="/login" element={<Login />}>
          </Route>
          <Route path="/admin" element={
              <ProtectedRoute >
                  <Admin />
              </ProtectedRoute>
              }>
          </Route>
        </Routes>
    </BrowserRouter>
  );
}
export default App;
1 Answers

Change PotectedRoute.js to the code below, as what you are doing is more like what we used to do for React Router Dom v5 while you are using v6.

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

export const ProtectedRoute = ({children}) => {
  let location = useLocation();
  if(!localStorage.getItem("loginEmail")){
    return <Navigate  to="/login" state={{ from: location }}  replace />;
  }
  return children;
};

The information from useLocation passed as prop to Navigate can be used in Login so you send the user to that specific url where they were going to instead of a hard coded one (admin in your case), useful if you had multiple protected routes. Though it's not a requirement, you can remove it.

To know more about authentication in React Router Dom v6, visit this example on StackBlitz from their documentation. Don't look at the editor lint errors, it's the most complete and straightforward authentication example.

Related