14

I am completely stuck when integrating PrivateRoute HOC in my react.js project.

Here is my route file

import React, { Component } from "react";
import { Route, Redirect, Switch, BrowserRouter as Router } from 'react-router-dom';
import Dashboard from "../view/Dashboard/Dashboard";
import Login from "../view/Login/Login";
import Admin from "../view/UserManagement/Admin";
import cookie from 'react-cookies'

const PrivateRoute = ({ component, ...rest }) => {
  const isAuthed = cookie.load('token')
  console.log(isAuthed, 'dddddddddddddddddddd')
  return (
    <Route {...rest} exact
      render = {(props) => (
        isAuthed ? (
          <div>
            {React.createElement(component, props)}
          </div>
        ) :
        (
          <Redirect
            to={{
              pathname: '/login',
              state: { from: props.location }
            }}
          />
        )
      )}
    />
  )
}

class MainPanel extends Component {

  render() {
    return (
      <div style={{ direction: direction }}> 
        <Router>
          <Switch>
            <Route path="/login" component={Login}/>
            <PrivateRoute path="/" component={Dashboard} />
            <PrivateRoute path="/AdminManagement" component={Admin} />
           </Switch>
        </Router>
      </div>
    )
  }
}
export default withNamespaces('common') (MainPanel);

I am totally break my head with this but didn't get rid out of that issue. Why my console inside the PrivateRoute doesn't show the values

Is there any issue with the react and react-router-dom versions

Thank you in advance!!!

Profer
  • 1,463
  • 3
  • 21
  • 53

3 Answers3

6

The PrivateRoute component that you have is correct, You however only need to re-order your Routes for them to work correctly. /AdminManagement route should come before / since Switch renders the first matching Route and a Route path will also match its prefix path

class MainPanel extends Component {

  render() {
    return (
      <div style={{ direction: direction }}> 
        <Router>
          <Switch>
            <Route path="/login" component={Login}/>
            <PrivateRoute path="/AdminManagement" component={Admin} />
            <PrivateRoute path="/" component={Dashboard} />
           </Switch>
        </Router>
      </div>
    )
  }
}
export default withNamespaces('common') (MainPanel);

Working demo

Shubham Khatri
  • 211,155
  • 45
  • 305
  • 318
  • Thank you... But It works partially. It is redirecting me to `/login` always. Why so? – Profer Feb 11 '19 at 07:32
  • @Profer because the localStorage must be set on login otherwise it will never work – Shubham Khatri Feb 11 '19 at 07:38
  • @Profer, were you able to solve the above issue with the above answer. – Shubham Khatri Feb 14 '19 at 10:46
  • @Profer, not worrying about award. I didn't receive any response from you after my last comment, thats the reason I wanted to confirm – Shubham Khatri Feb 14 '19 at 10:57
  • *didn't receive any response from you after my last comment* Apologies for that – Profer Feb 14 '19 at 11:06
  • `/AdminManagement route should come before / since Switch renders the first matching Route and a Route path will also match its prefix path`, so /AdmingManagement also matches `/` and hence Admin won't be rendered but Dashboard will always render in your case – Shubham Khatri Feb 18 '19 at 18:31
4

Here is how I handle my private routes, maybe it will help you also. I have protectedRoutes as an array with the routes. you can fit them as you like.

const routes = [
  {
    path: '/login', exact: true, name: 'Login', component: Login,
  },
];

const protectedRoutes = [
  {
    path: '/admin', exact: true, name: 'Admin', component: Admin,
  },
];

<Switch>

    {routes.map((route, idx) => (route.component ? (
         <Route
             key={idx}
             path={route.path}
             exact={route.exact}
             name={route.name}
             render={props => (
             <route.component {...props} />
             )}
          />
            )
     : (null)))}

     {protectedRoutes.map((route, idx) => (route.component ? (
          <Route
              key={idx}
              path={route.path}
              exact={route.exact}
              name={route.name}
              render={props => (
                isAuth
                  ? <route.component {...props} />
                  : <Redirect to="/login" />
                )}
           />
       )
       : (null)))}
        
</Switch>

LE: added full example based on the original code

import React, { Component } from 'react';
import { Route, Redirect, Switch, BrowserRouter as Router } from 'react-router-dom';
import Dashboard from '../view/Dashboard/Dashboard';
import Login from '../view/Login/Login';
import Admin from '../view/UserManagement/Admin';
import cookie from 'react-cookies';

const routes = [
  {
    path: '/login', exact: true, name: 'Login', component: Login,
  },
];

const protectedRoutes = [
  {
    path: '/', exact: true, name: 'Dashboard', component: Dashboard,
  },
  {
    path: '/AdminManagement', exact: true, name: 'Admin', component: Admin,
  },
];

class MainPanel extends Component {

  constructor(props) {
    super(props);
    this.state = {
      isAuthed: cookie.load('token'),
    },
  };

  render() {
    const { isAuthed } = this.state;
    return (
      <div style={{ direction: direction }}>
        <Router>
          <Switch>
            {routes.map((route, idx) => (route.component ? (
                <Route
                  key={idx}
                  path={route.path}
                  exact={route.exact}
                  name={route.name}
                  render={props => (
                    <route.component {...props} />
                  )}
                />
              )
              : (null)))}

            {protectedRoutes.map((route, idx) => (route.component ? (
                <Route
                  key={idx}
                  path={route.path}
                  exact={route.exact}
                  name={route.name}
                  render={props => (
                    isAuth
                      ? <route.component {...props} />
                      : <Redirect to="/login" />
                  )}
                />
              )
              : (null)))}
          </Switch>
        </Router>
      </div>
    )
  }
}

export default withNamespaces('common')(MainPanel);
Sabbin
  • 1,469
  • 1
  • 11
  • 25
  • 3
    This does not answer OP's question – Weedoze Feb 08 '19 at 14:41
  • 3
    It's just a different approach to the issue in hand. I agree that it does not answer the question but it may help to achieve the desired result. If not I will gladly remove the answer – Sabbin Feb 08 '19 at 14:43
2

try change library to react-cookie;

let PrivateRoute = ({ component: Component, cookies, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      cookies.get("name") ? (
        <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);

https://codesandbox.io/s/015k0jl0ql

Vadim Hulevich
  • 1,599
  • 6
  • 16