2

All of my main react components have some parts like this:

export default class ExampleMain extends Component {
    constructor(props) {
        super(props)
        this.state = {
            isAuthenticated: Meteor.userId() !== null
        }
    }

    componentWillMount() {
        if (!this.state.isAuthenticated) browserHistory.push('/login')
    }
    componentDidUpdate() {
        if (!this.state.isAuthenticated) browserHistory.push('/login')
    }
}

With this I am checking if a user is logged in. If this is false, the user will be redirected to login route. As this part is used in many components, I was thinking if I can optimize this to get a DRY code...

Update

I am using react router:

render((
    <Router history={ browserHistory }>
        <Route path='/' component={ App }>
            <IndexRoute component={ Main } />
            <Route path='login' component={ Login } />
            <Route path='content/:id' component={ Content } />
        </Route>
        <Redirect from='*' to='/' />
    </Router>
), document.getElementById('root'))
user3142695
  • 11,619
  • 29
  • 119
  • 238
  • Are you using Redux/React-Router? – Omri Aharon Feb 09 '17 at 21:24
  • I am using react router – user3142695 Feb 09 '17 at 21:25
  • You can check it once then, in the constructor of the component that is in a `Route` that is the parent of all of these components. – Omri Aharon Feb 09 '17 at 21:27
  • I've updated the question to show you my routing example... So you mean to check on the `App` component, right? – user3142695 Feb 09 '17 at 21:30
  • 1
    Yes. You can use `onEnter` hook as well, and make that logic and redirect even before you render the App component. But since `login` route is nested, hook won't help you too much unless you change your routes order. (since App would have to be rendered anyway, you might want login to be outside) – Omri Aharon Feb 09 '17 at 21:34

2 Answers2

2

You can try something like this:

<Router history={ browserHistory }>
    <Route path='/' component={ App }>
        <IndexRoute component={ Main } />
        <Route path='/login' component={ Login } />
        <Route path='content/:id' component={ Content } />
    </Route>
    <Redirect from='*' to='/' />
</Router>

And in App, using withRouter to "inject" the router inside your component:

import { withRouter } from 'react-router';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isAuthenticated: Meteor.userId() !== null
        }
    }

    componentWillMount() {
        if (!this.state.isAuthenticated) {
           this.props.router.push('/login');
        }
    }
}

export default withRouter(App);
Omri Aharon
  • 16,299
  • 3
  • 36
  • 54
  • just asking... App is my main component, which gives me the wrapping main layout. This is always the same (navigation bar, background image, and so on). Also on login page. So I think I have to render `App` and do the authenfication for all other components... – user3142695 Feb 09 '17 at 21:44
  • You know your app's needs best, disregard my Login route suggestion then and get it back nested in App. I'll edit. – Omri Aharon Feb 09 '17 at 21:45
  • Close to working... But if user is logged out I get the error `Warning: setState(...): Cannot update during an existing state transition` – user3142695 Feb 09 '17 at 22:06
  • @user3142695 Did this work out eventually or are you still getting that error ? – Omri Aharon Feb 10 '17 at 07:36
  • Can you try moving the `if (isAutheniticated` chunk to `componentWillMount` instead of the constructor? – Omri Aharon Feb 10 '17 at 07:50
1

Maybe this helps you. I would tried to use any hook before routing. But you always can extend your own class with such functionality like that example

function requireAuth(nextState, replace) {
  if (!auth.loggedIn()) {
    replace({
      pathname: '/login',
      state: { nextPathname: nextState.location.pathname }
    })
  }
}

render((
  <Router history={ browserHistory }>
    <Route path='/' component={ App }>
      <IndexRoute component={ Main } />
      <Route path='login' component={ Login } />
      <Route path='content/:id' component={ Content } onEnter={requireAuth} />
    </Route>
    <Redirect from='*' to='/' />
  </Router>
), document.getElementById('root'))

To see full code follow link above.

Community
  • 1
  • 1
zhukva
  • 11
  • 1
  • 2