Search code examples
firebasereact-nativereduxfirebase-authenticationreact-native-router-flux

Redirect loggedIn Firebase user to Main Component with react-native-router-flux


I'm trying to direct the user to Main Component every time the app starts up.

I use react-native-router-flux as my navigation wrapper, Firebase as backend and Redux as state management library.

Here's the problem. I do firebase.auth().onAuthStateChanged() in my Router Component to determine whether the user is loggedIn.

If there is no user, then return Login component.

If there is a user logged in, return Main Component, as the base component in the stack.

This SO POST has the exact problem and the answer proposed suggests using Switch Feature from react-native-router-flux. I gave it a shot, not helpful.

Here is my code.

App.js

import React, { Component } from 'react';

import firebase from 'firebase';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk'
import reducers from './reducers';

import Router from './Router';

class App extends Component {

  componentWillMount() {
    firebase.initializeApp({
      //my firebase config
    });
  }

  render() {
    const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));

    return (
      <Provider store={store}>
        <Router />
      </Provider>
    );
  }
}

export default App;

Router.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { isLoggedIn } from './actions';
import { Scene, Router, Actions, Switch } from 'react-native-router-flux';

import firebase from 'firebase';

import Login from './components/auth/Login';
import Register from './components/auth/Register';
import Main from './components/Main';

class RouterComponent extends Component {

  state = { loggedIn: false }

  componentWillMount() {
    this.props.isLoggedIn();
  }

  render() {
    return(
      <Router sceneStyle={{ }} hideNavBar={true}>
        <Scene key="root">
          <Scene key="authContainer" initial>
            <Scene key="login" component={Login} title="Login Page" />
            <Scene key="register" component={Register} title="Register Page" />
          </Scene>

          <Scene key="mainContainer">
            <Scene key="main" component={Main} title="Main Page" />
          </Scene>
        </Scene>
      </Router>
    )
  }
}

export default connect(null, { isLoggedIn })(RouterComponent);

Some of my redux action creators

export const isLoggedIn = (dispatch) => {
  return(dispatch) => {
    firebase.auth().onAuthStateChanged((user) => loginUserSuccess(dispatch, user));
  };
};

const loginUserSuccess = (dispatch, user) => {
  dispatch({
    type: LOGIN_USER_SUCCESS,
    payload: user
  });
  Actions.mainContainer({ type: 'reset'});
};

I understand the exact motivation can be achieved with the async snippet below:

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // return <Main />
  } else {
    // Stay at login screen
  }
});

but I'm trying to recreate it with react-native-router-flux.

Here's a gif-shot of my app to help you guys understand more. A user has already logged in. The Main screen is being dispatched after some time. Any thought? GIF


Solution

  • I don't know if there are any specific constraints in your app but I'm using a Splash screen (also disable the default one generated by Xcode) and perform authentication checking on this screen.

    If user logged in, reset the stack to Main component, otherwise reset the stack to Login component.