2

I have a React Native application which I have implemented. Currently the app opens up on a loading screen which after mounting checks the firebase.auth().onAuthStateChanged(...) feature.

The app basically decides whether or not to got to the login screen or to main screen depending on whether or not the user is already authenticated.

It is implemented like this:

Main Navigator:

const MainNavigator = TabNavigator({
  auth: {
    screen: TabNavigator({
      login: { screen: LoginScreen },
      signup: { screen: SignupScreen }
    }, {
      initialRouteName: 'login',
      tabBarPosition: 'top',
      lazy: true,
      animationEnabled: true,
      swipeEnabled: true,
      tabBarOptions: {
        labelStyle: { fontSize: 12 },
        showIcon: true,
        iconStyle: { width: 30, height: 30 } 
      }
    })
  },
  main: {
    screen: StackNavigator({
      notes: { screen: NotesScreen }
    }, {
      initialRouteName: 'notes'
    })
  },
  loading: { screen: LoadingScreen }
}, {
  initialRouteName: 'loading',
  lazy: true,
  swipeEnabled: false,
  animationEnabled: false,
  navigationOptions: {
    tabBarVisible: false
  }
});

Loading Screen:

class LoadingScreen extends Component {
  componentDidMount() {
    const { navigate } = this.props.navigation;

    firebase.auth().onAuthStateChanged(user => {
      if (user) {
        navigate('main');
      } else {
        navigate('auth');
      }
    });
  }

  render() {
    return (
      <View style={styles.spinnerStyle}>
        <Spinner size="large" />
      </View>
    );
  }
}

const styles = {
  spinnerStyle: {
    flexDirection: 'row',
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
};

This works well except for one issue.

When I press the hardware back button for Android, it goes to the application loading screen which obvious is undesired. How do I prevent that?

EDIT:

I've tried the following and it didn't work either:

const resetAction = (routeName) => NavigationActions.reset({
  index: 0,
  actions: [NavigationActions.navigate({ routeName })],
  key: null
});

class LoadingScreen extends Component {
  componentDidMount() {
    const { dispatch } = this.props.navigation;

    firebase.auth().onAuthStateChanged(user => {
      if (user) {
        this.props.setUser(user);
        dispatch(resetAction('main'));
      } else {
        dispatch(resetAction('auth'));
      }
    });
  }

  render() {
    return (
      <View style={styles.spinnerStyle}>
        <Spinner size="large" />
      </View>
    );
  }
}
Barry Michael Doyle
  • 9,333
  • 30
  • 83
  • 143

4 Answers4

1

Try a custom navigation component with custom back button support. Dont forget to add the reducer to yoru combine reducers function.

Create a navigation component:

import React, { Component } from 'react';
import { BackHandler } from 'react-native';
import { connect } from 'react-redux';
import { addNavigationHelpers } from 'react-navigation';
import MainNavigator from './MainNavigator';

class AppWithNavigationState extends Component {
  componentDidMount () {
    BackHandler.addEventListener('hardwareBackPress', () => {
      this.props.dispatch({
        type: 'Navigation/BACK'
      });

      return true;
    });
  }

  componentWillUnmount () {
    BackHandler.removeEventListener('hardwareBackPress');
  }

  render () {
    return (
      <MainNavigator navigation={addNavigationHelpers({
        dispatch: this.props.dispatch,
        state: this.props.nav
      })}/>
    );
  }
}

export default connect((state) => ({ nav: state.nav }))(AppWithNavigationState);

Create a navigation reducer:

import { NavigationActions } from 'react-navigation';
import MainNavigator from './MainNavigator';
import { NAVIGATION_ON_SIGN_IN } from '../redux/actions/ActionTypes';
import { BackHandler } from 'react-native';

const initialState = MainNavigator.router.getStateForAction(MainNavigator.router.getActionForPathAndParams('loading'));

function appShouldClose (nextState) {
  const { index, routes } = nextState;

  return index === 0 || routes[1].routeName === 'auth';
}

export default (state = initialState, action) => {
  const { router } = MainNavigator;
  let nextState;

  switch (action.type) {
    case NavigationActions.BACK:
      nextState = router.getStateForAction(action, state);
      appShouldClose(nextState) && BackHandler.exitApp();
      break;

    default:
      nextState = router.getStateForAction(action, state);
  }

  return nextState || state;
};
Lance
  • 701
  • 6
  • 25
  • Wow that was pretty overkill. Well if that's the only way then thanks! – Barry Michael Doyle Aug 25 '17 at 14:16
  • Sure. I do more then just back button handling so at least in the future if you need to add any more custom navigation implementation the boiler plate code is already set up. – Lance Aug 25 '17 at 15:04
1

use a switch navigator until the user logs in(loading and login page ) successsfully after that use a stack navigator(user homepage and otherpages which follow).

switchNavigator(loading, login, stackNavigator)

stackNavigator(user homepage,....)
0


it is my solution :)
I have StageArea page. it is bridge between from login to timeline . User is not login then go to LoginPage. User is login then go to Timeline. User press back button then again go to TimeLine page not go to login page .( Sory for my english)

import React, { Component } from 'react';
import { View  } from 'react-native';
import LoginForm from './LoginForm';
import Timeline from './Timeline';
import firebase from 'firebase';
import InitialPage from './InitialPage'
class StageArea extends  Component {


    state = {isLoggin:''};

    componentWillMount(){
        firebase.auth().onAuthStateChanged((user) => {
            if (user) {
                    this.setState({ isLoggin:true})
            }else {
                this.setState({ isLoggin:false})

            }
        })

    }

    render() {
        if(this.state.isLoggin)
        {
            return(<Timeline/>);

        }
        else if (this.state.isLoggin===false) {
            return(<LoginForm/>);
        }

    }
}

export default StageArea;
Burhan Yılmaz
  • 774
  • 8
  • 21
-2

Write the code below ,

   static navigationOptions = {
       header:null
     };

Just before

render() {
     return (

on the NotesScreen,There will not be any back button.

roy
  • 6,685
  • 3
  • 26
  • 39
Nipa sarker
  • 27
  • 1
  • 5