0

I have this <Switch> setup in my app:

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/login" component={Login} />
  <Route path="/logout" component={Logout} />
  <EnsureLoggedIn>
    <Route exact path="/user" component={User} />
  </EnsureLoggedIn>
  <Route component={NotFound} />
</Switch>

How the EnsureLoggedIn component works shouldn't be too important for my question, although I just want to mention that it does use the withRouter HOC to access the match, location, and history props for routing/redirecting purposes.

What I want to have happen is that the EnsureLoggedIn component only triggers for routes matched within it. So in this case, I'd only want a visit to /user to trigger it. Anything else should move on to the NotFound route instead.

What I find happens instead, is that as soon as /, /login and /logout aren't matched, EnsureLoggedIn matches, and gets mounted and rendered, and nothing ever makes it to NotFound.

How can I get the behavior that I want? Alternatively, am I going about this the wrong way, and should I "protect" my logged-in routes in an entirely different manner?

Alex
  • 3,429
  • 4
  • 36
  • 66
  • 1
    EnsureLoggedIn is directly rendered and hence won't check for Routes within it. Check the duplicate on how to write Authenticated Routes – Shubham Khatri Mar 29 '18 at 09:32

1 Answers1

1

I have a little different approach where I wrap the component to be rendered inside the Route.

So this is what my router looks like, note the component prop of Route.

<Router history={history}>
  <div>
    <Route component={Navbar} />
    <Switch>
      <Route path="/control" component={AuthRequired(ControlPage)} />
      <Route path="/login" component={RestrictedAccess(LoginPage)} />
      <Route path="/logout" component={AuthRequired(App)} />
      <Route path="/" component={App} />
    </Switch>
  </div>
</Router>

So this is how my HOC RestrictedAccess looks like:

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";

import { redirectAuthUser } from "../actions";

/*
  HOC that restricts access to certain routes.

  If user is logged in restricts access to pages he wouldn't
  see if he was a guest, 
  example: Redirect if logged in user tried to visit login.
*/

export default function(ComposedComponent) {
  class Authentication extends Component {
    static contextTypes = {
      router: PropTypes.object
    };

    componentWillMount() {
      if (this.props.token) {
        // this.context.router.push("/login");
        this.props.redirectAuthUser();
      }
    }

    componentWillUpdate(nextProps) {
      if (!nextProps.token) {
        // this.context.router.push("/login");
        this.props.redirectAuthUser(); // this is just an action creator                    
                                       // what it does is commented up
      }
    }

    render() {
      return <ComposedComponent {...this.props} />;
    }
  }

  const mapStateToProps = state => ({
    token: state.auth.userToken
  });

  const mapDispatchToProps = {
    redirectAuthUser
  };

  return connect(mapStateToProps, mapDispatchToProps)(Authentication);
}

Hope this helps!