Description::

I am working on reactJS app and using react-router-dom for routing. If user is not authenticate, it's go to "http://localhost:3000/login" and after successful login it's redirects to " http://localhost:3000/dashboard". After reloading this page it's shows me blank page.

To resolve this problem I have added "/app" after my base url, and now it comes before every routing url now inner pages routing is like "http://localhost:3000/app/dashboard". But I don't want to add "app" before every routing element, I need routing url should be, base_url/page routing path.

Blank page routing::

import React, { Component } from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';

const InitialPath = ({ component: Component, authUser, ...rest }) => {
   return (<Route
         {...rest}
         render={props =>
            authUser
               ? <Component {...props} />
               :
               <Redirect
                  to={{
                     pathname: '/login',
                     state: { from: props.location }
                  }}
               />
         }
      />
   )
}

class App extends Component {
   constructor(props) {
      super(props);
   }

   render() {
      let isUserLogggedIn = localStorage.getItem('isUserLoggedIn');
      const { location, match } = this.props;
      let url = location.pathname.split('/');
      if (location.pathname === '/login') {
         localStorage.clear();
      }
      if (location.pathname === '/') {
         if (!isUserLogggedIn) {
            return (<Redirect exact from='/' to={`${match.url}login`} />);
         } else {
            return (<Redirect exact from='/' to={`${match.url}app`} />);
         }
      }
      if ((url[1] !== "app") && (url[1] !== "login")) {
         return (<Redirect exact from={location.pathname} to={`${match.url}login`} />);
      }
      return (
         <>
            <BrowserRouter>
               <Switch>
                  <InitialPath
                     path={`${match.url}app`}
                     authUser={isUserLogggedIn}
                     component={DefaultLayout}
                     location={location}
                  />
                  <Route path='/login' component={Login} />
               </Switch>
            </BrowserRouter>
         </>
      );
   }
}

export default App;

If the "app" is removed from root, then its work continues and error appears.

ERROR::

Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

1 Answers

0
Ivan Burnaev On

I think there is problem not with urls.

Trying to handle localStorage stuff into a render method is not the best idea. You should use life-cycle-methods for it i.e. componentDidMount, componentDidUpdate.

Your App component seems to be overwhelmed by logic. The auth-logic should be into the Login component, when it (Login) mounts it should clear storage. When user successfully authenticates, it (Login) should save the session id to the storage.

The next thing is messing with locations by yourself is not necessary, let react-router to do it for you.

class App extends Component {
  componentDidUpdate () {
    this.setState({ isUserLoggedIn: !!localStorage.getItem("isUserLoggedIn") });
  }

  render () {
    const { isUserLogggedIn } = this.state;

    return (
      <BrowserRouter>
        <Switch>
          <InitialPath
            path="/dashboard"
            authUser={isUserLogggedIn}
            component={DefaultLayout}
            location={location}
          />
          <Route path="/login" component={Login} />
        </Switch>
      </BrowserRouter>
    );
  }
}

class Login extends Component {
  componentDidMount () {
    localStorage.removeItem("isUserLogggedIn");
  }

  render () {
    // some render stuff
    //
    // after successfull login
    // you should save `isUserLogggedIn` into localStorage 
    // and redirect to the main page
  }
}