How to reset TabNavigator when user logs out (from other screen)

Solution 1:

This should work in most cases:

componentWillReceiveProps(nextProps) {
    if ( nextProps.token == undefined || _.isNil(nextProps.token) ) {

        let action = NavigationActions.reset({
            index: 0,
            key: null,
            actions: [
                NavigationActions.navigate({routeName: 'Auth'})
            ]
        });

        nextProps.navigation.dispatch(action);
    }
    ...
}

Or try by enhancing your navigator with custom action:

const changeAppNavigator = Navigator => {
   const router = Navigator.router;

   const defaultGetStateForAction = router.getStateForAction;

   router.getStateForAction = (action, state) => {
       if (state && action.type === "RESET_TO_AUTH") {
          let payLoad = {
              index: 0,
              key: null,
              actions: [NavigationActions.navigate({routeName: "AuthStackNavigator"})]
          };

          return defaultGetStateForAction(NavigationActions.reset(payLoad), state);
          // or this might work for you, not sure:
          // return defaultGetStateForAction(NavigationActions.init(), state)
       }
       return defaultGetStateForAction(action, state);
  };

  return Navigator;
};

const screens = { ... }

RootTabNavigator = changeAppNavigator(TabNavigator(screens, {
  initialRouteName: ...,
  ...
}));

Then in your Menuo Screen do:

componentWillReceiveProps(nextProps) {
    if ( nextProps.token == undefined || _.isNil(nextProps.token) ) {

        nextProps.navigation.dispatch({type: "RESET_TO_AUTH"});
    ...

Solution 2:

What you need is to initialize the navigator to the initial state. You can do that with NavigationActions.init(). You can learn more about Navigations Actions here.

You can do this by creating a Custom Navigation Action, read more about them here.

Here's some code that would do that for you:

// First get a hold of your navigator
const navigator = ...

// Get the original handler
const defaultGetStateForAction = navigator.router.getStateForAction

// Then hook into the router handler
navigator.router.getStateForAction = (action, state) => {

  if (action.type === 'MyCompleteReset') {
     // For your custom action, reset it all
     return defaultGetStateForAction(NavigationActions.init())
  }

  // Handle all other actions with the default handler
  return defaultGetStateForAction(action, state)
}

In order to trigger your Custom Navigation Action, you have to dispatch it as follows from within your React Component:

  this.props.navigation.dispatch({
      type: "MyCompleteReset",
      index: 0
    })

Solution 3:

You can define custom navigation logic by extending the router. To accomplish what you want that you described in the project file hierarchy in your question you can do something like this below.

MainTabNavigator.js

...

RootTabNavigator.router.getStateForAction = (action, state) => {
  if (state && action.type === 'GoToAuthScreen') {
    return {
      ...state,
      index: 0,
    };
  }

  return RootTabNavigator.router.getStateForAction(action, state);
};

MainTabNavigator.router.getStateForAction = (action, state) => {
  if (state && action.type === 'GoToAuthScreen') {
    return {
      ...state,
      index: 0,
    };
  }

  return MainTabNavigator.router.getStateForAction(action, state);
};

MenuStackNavigator.router.getStateForAction = (action, state) => {
  if (state && action.type === 'GoToAuthScreen') {
    return {
      ...state,
      index: 0,
    };
  }

  return MenuStackNavigator.router.getStateForAction(action, state);
};

In the Menuo Screen file

componentWillReceiveProps(nextProps) {
  if ( nextProps.token == undefined || _.isNil(nextProps.token) ) {
    const goToAuthScreen = () => ({
      type: 'GoToAuthScreen',
    });

    nextProps.navigation.dispatch(goToAuthScreen);
    ...
  }
}