xtabbas
xtabbas

Reputation: 647

React Router onEnter not working as intended

I am building a basic react-login app for educational purposes and to authenticate a route I am using React-router's onEnter prop functionality

import axios from 'axios';    

var Authentication = (nextState, replace, callback) => {
    axios.get('/api/getuser')
    .then((res) => {
        if(res.data != '') {
          replace('account/wall')
        }
        callback()
    })
    .catch((err) => {
        callback()
    })

}

export default (
  <Route component={Root}  >
      <Route path='/' component={Home} onEnter={Authentication}/>
      <Route path='/login' component={Login} onEnter={Authentication}/> 
      <Route path='/signup' component={Registration} onEnter={Authentication}/> 
      <Route path='/account/wall' component={Wall}/>
      <Route path='*' component={Notfound} />
  </Route>

);

Everything is working as intended But it is beyond me why the router render the Home component for a blink second and THEN replace the route to /account/wall when I try / route after logging in?? Same thing happen if I try /login or /signup after logging in., Is there anyway to fix this behavior ??

I already tried to solve this by authenticating the user in componentWillMount method (which is not the react way i guess) by rendering empty <div> when checking for user but that also renders empty page for a blink second and not the correct way to do it.

So I just want to render /account/wall if user is authenticated without any middleware renders. What can I do??

Upvotes: 0

Views: 1836

Answers (2)

abhirathore2006
abhirathore2006

Reputation: 3745

I can't write the exact example because everyone's implementation differs, but I am going to right a HelloWrapper component example which wraps any component and if it receive the sayHello prop to true, it render the Hello instead of actual component, you can check the login props and redirect or show login component..in your case.

  1. Write a function to copy props form actual component to wrapper

HoistNonReactStatistics.tsx or jsx ( I use typescript)

    const REACT_STATICS = {
    childContextTypes: true,
    contextTypes: true,
    defaultProps: true,
    displayName: true,
    getDefaultProps: true,
    mixins: true,
    propTypes: true,
    type: true
    };

    const KNOWN_STATICS = {
    name: true,
    length: true,
    prototype: true,
    caller: true,
    arguments: true,
    arity: true
    };

    export default function hoistStatics(targetComponent, sourceComponent) {
    var keys = Object.getOwnPropertyNames(sourceComponent);
    for (var i = 0; i < keys.length; ++i) {
      const key = keys[i];
      if (!REACT_STATICS[key] && !KNOWN_STATICS[key]) {
        try {
          targetComponent[key] = sourceComponent[key];
        } catch (error) {}
      }
    }
    return targetComponent;
    }
  1. write wrapper function which will return wrapped component

     import * as React from 'react';
     import HoistNonReactStatistics from "./HoistNonReactStatistics"
     export function HelloWrapper(){
    
     return function HellowWrapComponent(DecoratedComponent) {
    
     class WrappendComponent extends React.Component<{sayHello?:boolean},{}>{
        constructor(props){
          super(props);
        }
        componentWillMount(){
         /** do some login check here and redirect if required **/
         }
        componentWillReceiveProps(nextProps){
         /** do some login check here and redirect if required **/
         }
       render(){
         if(this.props.sayHello){
           return <div>Hello</div>
         }else{
           return <DecoratedComponent />
         }
       }
     }
     /** if you use redux then also apply the connect method on return component so it get access to required auth reducer data**/
     return HoistNonReactStatistics(WrappendComponent,DecoratedComponent);
     }
    }
    
    1. create a const ( not sure if this step is required for jsx, however typescript doesn't allow to wrap a component directly because I didn't declare wrapper function to accept arguments

    export const requireHellow = HelloWrapper();

    1. now warp any component with function, I used it at the time of export but you can also do it in Route's component prop

    export default requireHellow(SomeComponent);

now whenever you use this SomeComponent and it has sayHello prop to true it will render Hello otherwise render the actual component

Upvotes: 1

<code>function requireAuth(nextState, replace,callback){
     var data = {
         token: store.getState().student.token,
         email: store.getState().student.email}
     makeUserRequest('post', data, '/api/auth')
     .then((res)=>{
            if (!res.data.success) {
                    replace({ nextPathname: nextState.location.pathname },  nextState.location.query)
            }
            callback()
     })
 }

return(
    <Router history={browserHistory}>
<Route path='/' component={app}>
  <IndexRoute  component={login} />
        <Route path='home' component={home} />
  <Route path='login' component={login} />
  <Route path='profile' component={profile} onEnter={requireAuth} />
</Route>

)

Upvotes: 0

Related Questions