Search code examples
reactjsreact-nativereact-navigationreact-navigation-stack

React Native: There is no route defined for key X Must be one of Y Z


I'm working on an app with the following routing structure:

root // tab navigator
  A // stack navigator
    A1
    A2 -> B
  B // stack navigator
    B1
    B2
    B3 -> C
  C

The root navigation consists of a tab navigator. Two of the routes on that tab navigator (A and B) contain stack navigators.

I'm trying to make it so that whenever users click the B tab, the B stack resets, so the user is always served B1 when the B stack mounts.

I thought I could accomplish this by adding the following event to the icon that users click to navigate to B (my tab component is custom):

this.props.navigation.dispatch(StackActions.reset({
  index: 0,
  key: null,
  actions: [NavigationActions.navigate({ routeName: 'B' })],
}));

However, this throws:

Error: There is no route defined for key B.
Must be one of: 'A','A1','A2'

This bamboozles me. Does anyone know how I can force the B stack to reset to 0 programmatically? Any suggestions would be helpful!

// versions:
"react-navigation": "^4.0.10",
"react-navigation-stack": "^1.9.4",
"react-navigation-tabs": "^2.5.6",

Solution

  • It's sketchy but I was able to get this running by saving the B router into a global namespace:

    const BStack = createStackNavigator(
      {
        B1: { screen: B1, },
        B2: { screen: B2, },
        B3: { screen: B3, },
      },
      { 
        initialRouteName: 'B1',
      }
    )
    
    BStack.navigationOptions = ({navigation}) => {
      global.B_NAVIGATOR = navigation; // could be stored in redux or elsewhere...
    }
    

    Then inside my root level tab navigator, I listened to hear if the user clicked the B tab. If so, I just reset the B stack navigator with .popToTop():

    class Tab extends React.Component {
      constructor(props) {
        super(props)
        this.handleClick = this.handleClick.bind(this)
      }
    
      handleClick() {
        if (global.B_NAVIGATOR) global.B_NAVIGATOR.popToTop();
        this.props.navigation.navigate('B', {});
      }
    
      render() {
        return (
          <TouchableOpacity onPress={this.handleClick}>
            <Text>Link to B</Text>
          </TouchableOpacity>
        )
      }
    }