this.props.navigation.navigate() doesn't work (using WithNavigation)

Viewed 6555

I have implemented a pop-up component in a header with More Options button. This button is available only on the UserProfileScreen. When you press on it you see two buttons: 'Settings' and 'Log out'. The issue is related to Settings button.

Expected behavior: Press on Settings button -> this.props.navigation.navigate('SettingsNavigator') is called -> SettingsScreen is shown

Actual behavior: Press on Settings button -> console.warn('go to settings') is called and nothing more (you are not redirected to SettingsScreen).

SettingsNavigator.js

import React from 'react';
import { createStackNavigator } from 'react-navigation';

import SettingsScreen from './SettingsScreen';
import EditProfileScreen from './EditProfileScreen';
import RemoveProfileScreen from './RemoveProfileScreen';

const SettingsNavigator = createStackNavigator({
    SettingsScreen: SettingsScreen,
    EditProfile: EditProfileScreen,
    RemoveProfile: RemoveProfileScreen
}, {
    initialRouteName: 'SettingsScreen'
});

export default SettingsNavigator;

optionHeaderButton.js

import { withNavigation } from 'react-navigation';
...

class OptionsHeaderButton extends Component {

    ...

    navigateToSettings = () => {
        console.warn('go to settings')
        this.props.navigation.navigate('SettingsNavigator');
    }

    render() {
    return(
        <Menu onSelect = {value => {
            switch(value) {
                case 'Settings':
                    this.navigateToSettings();
                    break;
                case 'Logout':
                    this.onLogOutPress();
                    break;
            }
        }}>

            <MenuTrigger>
                <Icon name = 'dots-vertical' size = {24} color = {text}/>
            </MenuTrigger>

            <MenuOptions style = {optionsHeaderButtonStyle.menuWrapper}>

                <MenuOption value = {'Settings'}>
                    <View style = {optionsHeaderButtonStyle.optionWrapper}>
                        <View style = {optionsHeaderButtonStyle.optionIcon}>
                            <IconSimpleLine name = 'settings' size = {12} color = {text}/>
                        </View>
                        <Text style = {[optionsHeaderButtonStyle.option, optionsHeaderButtonStyle.lastOption]}>
                            Settings
                        </Text>
                    </View>
                </MenuOption>

                <MenuOption value = {'Logout'}>
                    <View style = {optionsHeaderButtonStyle.optionWrapper}>
                        <View style = {optionsHeaderButtonStyle.optionIcon}>
                            <IconSimpleLine name = 'logout' size = {12} color = {text}/>
                        </View>
                        <Text style = {[optionsHeaderButtonStyle.option, optionsHeaderButtonStyle.lastOption]}>
                            Logout
                        </Text>
                    </View>
                </MenuOption>

            </MenuOptions>

        </Menu>
    )
}
}

export default withNavigation(OptionsHeaderButton);

OptionsHeaderButton is nested to a Header Component that is nested in UserProfile Component.

As far as I know using withNavigation() I can call navigation.navigate() from any component. So why doesn't it work?

UPDATE:

After investigation I found that this issue is related to a bug of React Navigation that was found on April of 2017. It means that you can use navigation.navigate() only inside one Stack. But I can't find any info about fix of this bug.

4 Answers

you need to pass screen name instead of navigator.

this.props.navigation.navigate('SettingsSecreen');

try this:

import { NavigationActions, withNavigation } from 'react-navigation';



navigateToSettings = () => {
  const navigateAction = NavigationActions.navigate({ routeName: 'SettingsScreen' });
  this.props.navigation.dispatch(navigateAction);
}

I had this issue but I have wired up my App.js slightly differently using stack navigation and drawer navigation (And switch navigation for auth) - mostly followed the react navigation docs:

App.js

const AuthStack = createStackNavigator({ Login: Login }, { headerMode: 'none' });
const ActivityStack = createStackNavigator({ Activity: ActivityScreen}, {headerMode: 'none'});

// setup my routing & config here

export default createAppContainer(createSwitchNavigator(
{
   Auth: AuthStack,
   ActivityStack: ActivityStack,
},
{
   intitalRouteName: 'Auth',
},
));

In the screen I want to navigate from I wire up the constructor like this (to bind the navigation function):

FirstScreen.js

export default class FirstScreen extends React.Component {
  constructor(props) {
    super(props);

    this.navigateToScreen = this.navigateToScreen.bind(this);
  }

state = {
   // state items here
}

  navigateToScreen(screenName) {
    this.props.navigation.navigate(screenName);
  }

  render() {
    return (
      <View style={styles.container}>
        <TouchableOpacity style={styles.button} onPress= 
              {this.navigateToScreen("Activity")}>
          <Text style={styles.loginText}>
            ADD ACTIVITY
          </Text>
        </TouchableOpacity>
      </View>

Note how I am calling the navigation, I am only passing in the route alias I gave earlier in the App.js file:

    Activity: ActivityStack,

So I would write this.navigateToScreen("Activity") from the calling point passing in the alias not the screen name or stack name.

This navigates correctly to the screen and utilizes stack navigation I defined earlier in App.js.

Hope this makes sense (parent child hierarchy is achieved by nesting the various navigation features like switch, stack and drawer to achieve your desired results.

in react-navigation Version: 5.x withNavigation is not working. To fix this issue try this.

import { useNavigation } from '@react-navigation/native';
const navigation = useNavigation();
navigation.navigate("DetailsScreen")

no need to warp the component in withNavigation.

Hope this may helps.

Related