galgo
galgo

Reputation: 764

Reactjs react-router Authenticate failling

I am new to ReactJS and sorry if this question was asked before, I don't know where to start.

I followed the Auth guidelines in: https://reacttraining.com/react-router/web/example/auth-workflow

I am using react-router to handle navigation with ReactJS, I have an index.js file that handles the navigation and includes:

import {BrowserRouter, Redirect, Route} from 'react-router-dom';
import Auth from './components/Auth';

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    Auth.authenticate((auth) => {
      if (auth) {
        (<Component {...props}/>)
      }
      else {
        (<Redirect to={{
          pathname: '/',
          state: { from: props.location }
        }}/>)
      }
    })
  )}/>
)

const App = () => (<BrowserRouter>
  <div>
    {/* PUBLIC */}
      <Route path={'/'} exact component={Inicio}/>
      <Route path={'/login'} component={Login}/>

    {/* PRIVATE */}
      <PrivateRoute path="/dashboard" component={Dashboard}/>

  </div>
</BrowserRouter>);

ReactDOM.render(<App/>, document.getElementById('root'));

Navigates fine, but the Authentication in Auth.authenticate((auth).. isn't working properly and throws an error.

It refers to a file that has the following:

import React from 'react';
import http from '../services/http';

const Auth = {
  authenticate(cb) {
    http.authenticate((e, auth) => {
      if (auth === true) {
        cb(true);
      }
      else {
        cb(false);
      }
    });
  }
}

export default Auth;

http.aunthenticate is a method with a callback, that works fine.

Yet I get the following error message in the console:

> The above error occurred in the <Route> component:
>     in Route (created by PrivateRoute)
>     in PrivateRoute (created by App)
>     in MuiThemeProvider (created by App)
>     in div (created by App)
>     in Router (created by BrowserRouter)
>     in BrowserRouter (created by App)
>     in App
> 
> Consider adding an error boundary to your tree to customize error
> handling behavior. Visit https://reactjs.org/docs/error-boundaries.html to learn
> more about error boundaries. react-dom.development.js:9747 Error:
> Route(...): Nothing was returned from render. This usually means a
> return statement is missing. Or, to render nothing, return null.

Any ideas? Thanks!

Upvotes: 0

Views: 453

Answers (2)

CodingNagger
CodingNagger

Reputation: 1568

Your PrivateRoute component never returns anything. Auth.authenticate((auth) =>... this is asynchronous therefore it's the same as if your method was empty in terms of render response. You should avoid doing that and simply have a property to detect whether or not the account is logged in or not. Per example this is how I wrote my PrivateRoute component using Facebook's Flux store.

const PrivateRoute = ({ component: Component, ...rest }) => (
    <Route {...rest} render={props => (
      AccountStore.loggedIn ? (
        <Component {...props} />
      ) : (
          <Redirect to={{
            pathname: '/signin',
            state: { from: props.location }
          }} />
        )
    )} />
  )

Here my component will always return something based off the account state being calculated prior to the rendering.

EDIT: Adding my AccountStore below for a bit more clarity on the specifics, Here I use a jwt token received after authenticatingn through a remote api and use whether or not it's set to determine if the user is logged in or not. However, it can be any property/value you pick. Could even be a class not connecting to anything and just flipping the user login status through a couple methods.

import Immutable from 'immutable';
import { ReduceStore } from 'flux/utils';
import AccountActionTypes from './AccountActionTypes';
import CoreDispatcher from '../CoreDispatcher';

import LocalStorage from '../../io/LocalStorage';

class AccountStore extends ReduceStore {
  constructor() {
    super(CoreDispatcher);

    this._jwt = LocalStorage.getItem('jwt');
  }

  getInitialState() {
    return Immutable.OrderedMap({
      jwt: this._jwt,
    });
  }

  reduce(state, action) {
    switch (action.type) {
      case AccountActionTypes.USER_DETAILS_IN:
        console.log('user details in');
        this._user = action.user;
        return state.set('user', this._user);

      case AccountActionTypes.USER_LOGGED_IN:
        this._jwt = action.jwt;
        return state.set('jwt', this._jwt);

      case AccountActionTypes.USER_LOGGED_OUT:
        this._jwt = null;
        return state.set('jwt', this._jwt);

      default:
        return state;
    }
  }

  get jwt() {
    return this._jwt;
  }

  get loggedIn() {
    return !!this._jwt;
  }
}

export default new AccountStore();

More details to use Flux Stores and Dispatcher there: https://facebook.github.io/flux/

Upvotes: 2

Stefan
Stefan

Reputation: 175

It loos like a simple syntax error:

const Auth = {
  authenticate(cb) {
    http.authenticate((e, auth) => {
      if (auth === true) {
        cb(true);
      }
      else {
        cb(false);
      }
    });
  }
}

You need to define Auth as a valid React component (either a class or function). What you have there is not a valid class, function, or object.

More importantly if Auth is not rendering some jsx then it should not be a React component. HTTP requests should be defined as a class method, and called inside of a life-cycle hook, most commonly componentDidMount(). Article explaining how to make AJAX requests in react.

Upvotes: 0

Related Questions