React router check if used is logged before rendering


#1

hello everyone

i have an app component that is rendering correctly with react router, but now i’m having trouble with checking if user is logged and redirecting to the /signin route, here’s the code i added to the app component:

  componentWillMount() {
      if (!Meteor.user()) {
        browserHistory.push('/signin');
      }
    }

it works only when there’s no account, but when the user is logged it stills redirects to the signin route

any ideas ?

thanks in advance

John


#2

Maybe you can find a solution to this between Sashko’s answer here Problem requiring user authentication for route using React Router + React and routes.js in https://github.com/themeteorchef/base


#3

I do this with react router from the onEnter hook, just a slight adaption of https://github.com/themeteorchef/base

react router - routes.jsx

...

const requireAuth = (nextState, replace) => {
  if (!Meteor.loggingIn() && !Meteor.userId()) {
    replace({
      pathname: '/login',
      state: { nextPathname: nextState.location.pathname },
    });
  }
};

...

<Route path="/private" component={PrivateContainer} onEnter={ requireAuth }/>

...

login form submit handler - Login.jsx

...

handleSubmit(doc) {
        Meteor.loginWithPassword(doc.email, doc.password, (err) => {
          if (err) {
            //display error
          } else {
            const location = this.props.location;
            if (location && location.state && location.state.nextPathname) {
              browserHistory.push(location.state.nextPathname);
            } else {
              browserHistory.push('/');//default router after logged 
            }
          }
        });
      }

...

it seems to work well and it’s nice to send the user back to the url they requested before you sent them to sign in.


#4

IMHO your router’s only job should be to route, and it should not have to worry about users or subscriptions.

You should do that in your app’s global container. So the flow should be:

  1. Wait for current user and any other global subscription to be done loading.
  2. Load the app.
  3. Load the component.

Now you know the current user will be available to your component (I use React’s context to access it but there are other ways), and your router can remain “dumb”.


#5

thanks guys, onEnter hook with requireAuth function worked perfectly ! =)


#6

makes sense, do you have an example of that flow to check it out ? i’m having trouble with checking that on the container as sometimes it runs the function while logging in some other times afterwards so it’s not consistent, also React docs advice not to use context =/


#7

You can see how the container is set up in Nova:

https://github.com/TelescopeJS/Telescope/blob/devel/packages/nova-core/lib/containers/AppComposer.jsx

It’s then used here:

https://github.com/TelescopeJS/Telescope/blob/devel/packages/nova-base-components/lib/common/App.jsx

If you don’t want to use context you can check out how Mantra does it:

But personally I think using context is fine, even if you do end up having to refactor it one day it’s worth it for the time you’ll save now compared to other, more complex patterns.


#8

will definitely check it out, thanks for the suggestion mate :+1: