React Router 4 Async Rendering

1.8k Views Asked by At

I am following the guide on React Router 4 for Redirect(Auth) and I am having trouble rendering base on the promise the ajax returns. I'm not sure why my rendering inside the promise is not being returned. Could someone point me to the right direction?

import React from 'react';
import {
  Route,
  Redirect,
  withRouter
} from 'react-router-dom';
import HeaderContainer from '../containers/HeaderContainer';

const PrivateRoute = ({ component: Component, ...props }) => {

  const validated = (rest) => {
    props.fetchUser()
    .then(() => {
      return (
        <div>
          <HeaderContainer />
          <Component {...rest}/>
        </div>
      )
    })
    .catch(()=> {
      return (
        <Redirect to={{
          pathname: '/signin',
          state: { from: props.location }
        }}/>
      )
    }
    );
  }

  return (
    <Route {...props} render={rest => {
      return (
        <div>
          { validated(rest) }
        </div>
      )
    }}/>
  )
}

export default withRouter(PrivateRoute);

My routes look like this

const Root = ({ store }) => {
  return (
    <Provider store={ store }>
       <BrowserRouter onUpdate={() => window.scrollTo(0, 0)}>
          <div className="root">
            <Switch>
              <Route exact path="/signin" component={SignInContainer}/>
              <PrivateRouteContainer exact path="/" component={HomePageContainer} />
            </Switch>
          </div>
       </BrowserRouter>
    </Provider>
  )
};
1

There are 1 best solutions below

1
On

Thats because promise cannot return value, it only returns Promise. Instead it execute callbacks. Here is some explanation.

You could rearrange your code to somewhat like this:

class PrivateRoute extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      isFetching: true,
      isSuccess: null,
    };
  }

  componentDidMount() {
    this.props.fetchUser()
      .then(() => {
        this.setState({ isFetching: false, isSuccess: true });
      })
      .catch(()=> {
        this.setState({ isFetching: false, isSuccess: false });
      });
  }

  render() {
    const { isFetching, isSuccess } = this.state;    
    return (
      <Route {...this.props} render={rest => {
        const success = (
          <div>
            <HeaderContainer />
            <Component {...rest}/>
          </div>
        );

        const error = (
          <Redirect to={{
            pathname: '/signin',
            state: { from: this.props.location }
          }}/>
        );

        if(isFetching) {
          return null;
        }

        return isSuccess ? success : error;
      }}/>
    )
  } 
}

Notice that Promise doesn't return anything it just executing a callback which triggers rerender with new data in state.