leabum
leabum

Reputation: 395

React App redirects to route "/" when I try to navigate by changing url manually

I am creating a React app, that stores the users role (there are two possible roles 0, and 1 which are being used for conditional rendering) in a "global" React Context. The role gets assigned upon login. I am also using React Router to handle Routing, and wrote a ProtectedRoute component. My Problem is the following: When I am navigating via the NavBar all works perfectly fine, but when I enter e.g. /home into the url I get redirected to the LoginPage(which is the standard route when the role is not set to 0 or 1) and I can not access the other Routes anymore. However, the user does not get logged out (The session in the database is not being deleted), the app just seems to forget the global state "role", which is used to determine whether the user is allowed to access the individual routes. I am afraid my knowledge of the DOM and Router is too limited to solve this problem.

function App() {
  return (
    <AuthProvider>
      <Router>
          <NavigationBar />
          <AuthContext.Consumer>
            {context => (
              <React.Fragment>
                {!context.isAuthenticated() ? <Jumbotron/> : null}
              </React.Fragment>
            )}
          </AuthContext.Consumer>
          <Layout>
            <Switch>
              <Route exact path="/" component={() => <LandingPage />} />
              <ProtectedRoute path="/home" component={Home} />
              <ProtectedRoute path="/about" component={About}/>
              <ProtectedRoute path="/account" component={Account} />
              <ProtectedRoute path="/calender" component={Calender} />
              <ProtectedRoute path="/xyz" component={Xyz} />
              <ProtectedRoute path="/wasd" component={wasd} role={0} />
              <Route component={NoMatch} />
            </Switch>
          </Layout>
      </Router>
    </AuthProvider>
  );
}


export default App;
export const ProtectedRoute = ({ component: Component, ...rest }) => {
  const { isAuthenticated, getRole } = useContext(AuthContext);

  if (rest.role === 0) {
    return (
      <Route
        {...rest}
        render={props =>
          getRole() === 0 ? (
            <Component {...props} />
          ) : (
            <Redirect
              to={{
                pathname: "/404",
                state: {
                  from: props.location
                }
              }}
            />
          )
        }
      />
    );
  } else if (rest.role === 1) {
    return (
      <Route
        {...rest}
        render={props =>
          getRole() === 1 ? (
            <Component {...props} />
          ) : (
            <Redirect
              to={{
                pathname: "/404",
                state: {
                  from: props.location
                }
              }}
            />
          )
        }
      />
    );
  } else {
    return (
      <Route
        {...rest}
        render={props =>
          isAuthenticated() ? (
            <Component {...props} />
          ) : (
            <Redirect
              to={{
                pathname: "/",
                state: {
                  from: props.location
                }
              }}
            />
          )
        }
      />
    );
  }
};
import React from "react";

const AuthContext = React.createContext();

export default AuthContext;

class AuthProvider extends Component {
  constructor() {
    super();
    this.state = {
      role: 2, //none=2
      name: "",
      email: ""
    };
  }

  render() {
    return (
      <AuthContext.Provider
        value={{
          state: this.state,
          isAuthenticated: () => {
            if (this.state.role === 1 || this.state.role === 0) {
              return true;
            }
            return false;
          },
          setRole: newRole =>
            this.setState({
              role: newRole
            }),
          getRole: () => {
            return this.state.role;
          },
          setName: newName =>
            this.setState({
              name: newName
            }),
          getName: () => {
            return this.state.name;
            },
          setEmail: newEmail =>
            this.setState({
              email: newEmail
            }),
          getEmail: () => {
            return this.state.email;
            },
        }}
      >
        {this.props.children}
      </AuthContext.Provider>
    );
  }
}

export default AuthProvider;

Upvotes: 2

Views: 1813

Answers (1)

Brian Thompson
Brian Thompson

Reputation: 14355

If you are entering the url directing into the browser, React will reload completely and you will lose all state whether 'global' or otherwise. The most likely scenario is that your router is trying to validate your ability to view a component before you have your auth data.

You don't include how you get your auth session from the database, but even if you refetch the auth session, there is going to be a period where your app has mounted, but you don't have the response yet. This will cause your protected route to believe you are unauthorized, and redirect to the fallback path.

Try adding a check either inside your protected route or before the router itself, that blocks rendering until your auth data is loaded. Although upon reading your question again, it seems like you may not be refetching your logged in user at all.

Upvotes: 2

Related Questions