Navigate to root screen from nested stack navigato

2020-04-14 07:55发布

i am new to react and trying to learn it by myself , i am facing problem in navigating user back to root screen from nested stck navigator screen .

Here is some of my classes :-

index.android.js :-

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  StatusBar,
  View
} from 'react-native';
import {LoginStack} from './login/loginregisterrouter';
import {StackNavigator } from 'react-navigation';
class reactNavigationSample extends Component {
  render(){
    return (
   <LoginStack/>
    );
  }
}
AppRegistry.registerComponent('MssReactDemo', () => reactNavigationSample);

loginregisterrouter :-

import React from 'react';
import {StackNavigator } from 'react-navigation';
import LoginScreen from './LoginScreen';
import RegisterScreen from './RegisterScreen';
import NavigationContainer from './navigationContainer';
export const LoginStack = StackNavigator({
  LoginScreen: {
    screen: LoginScreen,
    navigationOptions: {
      title: 'LoginScreen',
    }
  },
  RegisterScreen: {
    screen: RegisterScreen,
    navigationOptions: ({ navigation }) => ({
      title: 'RegisterScreen',
    }),
  },NavigationContainer: {
        screen: NavigationContainer,
        navigationOptions: ({ navigation }) => ({
          title: 'NavigationContainer', header: null,
        }),
      },
});

Navigationcontainer.js :-

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  StatusBar,
  View
} from 'react-native';
import {EasyRNRoute,} from '../parent';
import {StackNavigator } from 'react-navigation';
export default class NavigationContainer extends Component {
  render(){
    return (
   <EasyRNRoute/>
    );
  }
}

parent.js :-

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  StatusBar,
  View
} from 'react-native';
import App from './app';
import DrawerMenu from './Drawer/drawer-toolbar-android';
import BookmarkView from './Pages/bookmark';
import ClientView from './Pages/client';
import InfoView from './Pages/info';
import SettingsView from './Pages/setting';
import { DrawerNavigator, StackNavigator } from 'react-navigation';

export const stackNavigator = StackNavigator({
  Info: { screen: InfoView },
  Settings: {screen: SettingsView },
  Bookmark: {screen: BookmarkView },
  Connections: {screen: ClientView},
}, {
  headerMode: 'none'
});

export const EasyRNRoute = DrawerNavigator({
  Home: {
    screen: App,
  },
  Stack: {
    screen: stackNavigator
  }
}, {
  contentComponent: DrawerMenu,
  contentOptions: {
    activeTintColor: '#e91e63',
    style: {
      flex: 1,
      paddingTop: 15,
    }
  }
});

Drawer-toolbar-android.js :-

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    StatusBar,
    View
} from 'react-native';
import { NavigationActions } from 'react-navigation'
import { COLOR, ThemeProvider, Toolbar, Drawer, Avatar } from 'react-native-material-ui';
import Container from '../Container';
import LoginScreen from '../login/LoginScreen';

const uiTheme = {
    palette: {
        primaryColor: COLOR.green500,
        accentColor: COLOR.pink500,
      },
    toolbar: {
        container: {
            height: 70,
            paddingTop: 20,
          },
      },
      avatar: {
          container: {
              backgroundColor: '#333'
          }
      }
  };

export default class DrawerMenu extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
        active: 'people',
      };
  }
handleLogoutPress = () => {
//    AsyncStorage.setItem('SignedUpuser', '');
this.props
               .navigation
               .dispatch(NavigationActions.reset(
                 {
                    index: 0,
                    actions: [
                      NavigationActions.navigate({ routeName: 'LoginScreen'})
                    ]
                  }));
//     this.props.navigation.dispatch(NavigationActions.back());
  };
  _setInfoActive() {
    this.setState({ active: 'info' });
  }

  render() {
    return (
        <ThemeProvider uiTheme={uiTheme}>
                <Container>
                    <StatusBar backgroundColor="rgba(0, 0, 0, 0.2)" translucent />
                    <Toolbar
                    leftElement="arrow-back"
                    onLeftElementPress={() => this.props.navigation.navigate('DrawerClose')}
                    centerElement="Menu"
                />
                    <View style={styles.container}>
                        <Drawer>
                            <Drawer.Header >
                                <Drawer.Header.Account
                                style={{ 
                                    container: { backgroundColor: '#fafafa' },
                                }}
                                avatar={<Avatar text={'S'} />}
//                                accounts={[
//                                    { avatar: <Avatar text="H" /> },
//                                    { avatar: <Avatar text="L" /> },
//                                ]}
                                footer={{
                                    dense: true,
                                    centerElement: {
                                        primaryText: 'Siddharth',
                                        secondaryText: 'I am DONE now',
                                    },

                                  }}
                            />
                            </Drawer.Header>
                            <Drawer.Section
                            style={{
                                label: {color: '#0000ff'}
                            }}
                            divider
                            items={[
                                {
                                    icon: 'bookmark-border', value: 'Bookmarks',
                                    active: this.state.active == 'bookmark',
                                    onPress: () => {
                                        this.setState({ active: 'bookmark' });
                                        this.props.navigation.navigate('Bookmark');
                                      },
                                  },
                                {
                                    icon: 'people', value: 'Connections',
                                    active: this.state.active == 'Connection',
                                    onPress: () => {
                                        this.setState({ active: 'Connection' });
                                        this.props.navigation.navigate('Connections');
                                      },
                                  },
                            ]}
                        />
                            <Drawer.Section
                            title="Personal"
                            items={[
                                {
                                    icon: 'info', value: 'Info',
                                    active: this.state.active == 'info',
                                    onPress: () => {
                                        this.setState({ active: 'info' });
                                        //this.props.navigation.navigate('DrawerClose');
                                        this.props.navigation.navigate('Info');
                                      },
                                  },
                                {
                                    icon: 'settings', value: 'Settings',
                                    active: this.state.active == 'settings',
                                    onPress: () => {
                                        this.setState({ active: 'settings' });
                                        this.props.navigation.navigate('Settings');
                                      },
                                  },
                                   {
                                    icon: 'logout', value: 'Logout',
                                    active: this.state.active == 'logout',
                                    onPress: () => {
                                    this.handleLogoutPress();
                                     },
                                      },
                            ]}
                        />
                        </Drawer>
                    </View>
                </Container>
            </ThemeProvider>
    );
  }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
      },
    header: {
        backgroundColor: '#455A64',
      },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
      },
    instructions: {
        textAlign: 'center',
        color: '#333333',
        marginBottom: 5,
      },
  });

The above is the stack architecture i am using inside my application and as you can see that my Main screen is LOGIN screen and i do have option for LOGOUT from application in my Drawer(side menu). What i eaxtly want is that when user click on logout he/she should get redirected to LOGIN screen . i have googled about this and got to know about two ways of doing it , but both the ways are not working for me , may be i am using them in wrong way. so i am here to seek your help .

The two methods are :-

1)

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

2) this.props.navigation.dispatch(NavigationActions.back());

this question may seems silly to you but i am really stuck at this point and just want to know how can i figure this out.Any help would be greatly Appreciated!!!! Thanks in advance.

4条回答
三岁会撩人
2楼-- · 2020-04-14 08:04

As per react navigation doc you can go to any stack by following ways: check the following link for more details React-navigation stack action link

1. import { StackActions, NavigationActions } from 'react-navigation';
         const resetAction = StackActions.reset({
          index: 0,
          actions: [NavigationActions.navigate({ routeName: 'Profile' })],
        });
        this.props.navigation.dispatch(resetAction);
  1. If you have a stack for profile then you can also go through like this check following link nested react navigation

import { NavigationActions } from 'react-navigation';

const navigateAction = NavigationActions.navigate({
  routeName: 'Profile',

  params: {},

  action: NavigationActions.navigate({ routeName: 'SubProfileRoute' }),
});

this.props.navigation.dispatch(navigateAction);

查看更多
成全新的幸福
3楼-- · 2020-04-14 08:08

(React Navigation 5.x) I had the problem of conditionally rendering the Screens like the example in "https://reactnavigation.org/docs/en/auth-flow.html" As I understand, meant that the Stack navigators were not "rendered" and thus are not able to find each other. What I did was the below and in the logout page:

navigation.replace('SplashScreen')

My logic was: SplashScreen (Check for AsyncStorage Token),

if (token){
navigation.navigate('App')
}else{
navigation.navigate('StartScreen')
}

In StartScreen, just navigate to Signin or Register where you go back to App if login is successful.

As a reference,

function AppBottomNavigator(){
  return(
    <AppNavigator.Navigator 
      initialRouteName={'Home'} ...}>
        <AppNavigator.Screen name='A' component={ScreenA}/>
        <AppNavigator.Screen name='B' component={ScreenB}/>
        <AppNavigator.Screen name='C' component={ScreenC}/>
        <AppNavigator.Screen name='D' component={ScreenD}/>
        <AppNavigator.Screen name='E' component={ScreenE}/>
    </AppNavigator.Navigator>
  )
}

export default App stuff...

 ...return(
        <AuthContext.Provider value={authContext}>
          <NavigationContainer>
            <AuthStack.Navigator screenOptions={{headerShown:false}}>
              <>
                <AuthStack.Screen name='SplashScreen' component={SplashScreen}/>
                <AuthStack.Screen name='StartScreen' component={StartScreen} />
                <AuthStack.Screen name='SignIn' component={SignIn} />
                <AuthStack.Screen name='Register' component={Register} />
                <AuthStack.Screen name='App' component={AppBottomNavigator}/>
              </>
            </AuthStack.Navigator>
          </NavigationContainer>
        </AuthContext.Provider>
      )

I am also quite new to this but it worked so if someone else has a safer/tidier/general solution, I would quite like to know, too.

查看更多
Luminary・发光体
4楼-- · 2020-04-14 08:16

After trying almost everything, I've found the solution that worked for me:

  this.props.navigation.popToTop(); // go to the top of the stack
  this.props.navigation.goBack(null); // now show the root screen
查看更多
\"骚年 ilove
5楼-- · 2020-04-14 08:18

Modal StackNavigator containing a Dismissable StackNavigator

Requires: react-navigation version: 1.0.0

Goal: Navigate from App TabNavigator to Screen 1 to Screen 2 to Screen N and then directly back to App TabNavigator.

Navigation hierarchy:

  • RootNavigator StackNavigator {mode: 'modal'}
    • App TabNavigator
      • TabA Screen
      • TabB Screen
      • TabC Screen
    • ModalScreen Screen
    • ModalStack DismissableStackNavigator
      • Screen 1 ModalStackScreen
      • Screen 2 ModalStackScreen
      • Screen N ModalStackScreen

Demo

Dismissable StackNavigator

package.json

{
  "name": "HelloWorld",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "jest"
  },
  "dependencies": {
    "react": "16.0.0-alpha.6",
    "react-native": "0.44.0",
    "react-navigation": "^1.0.0"
  },
  "devDependencies": {
    "babel-jest": "20.0.3",
    "babel-preset-react-native": "1.9.2",
    "jest": "20.0.3",
    "react-test-renderer": "16.0.0-alpha.6"
  },
  "jest": {
    "preset": "react-native"
  }
}

index.ios.js (or index.android.js)

import React from 'react'
import {
  AppRegistry,
  Button,
  Text,
  View
} from 'react-native'
import {
  StackNavigator,
  TabNavigator
} from 'react-navigation'

class TabA extends React.Component {
  state = {
    startScreen: 'none',
    returnScreen: 'none'
  }
  render () {
    return (
      <View style={{ padding: 40, paddingTop: 64 }}>
        <Text style={{ fontSize: 20 }}>{this.constructor.name}</Text>
        <Text>startScreen: {this.state.startScreen}</Text>
        <Text>returnScreen: {this.state.returnScreen}</Text>
        <Button
          title="Open ModalScreen"
          onPress={() => this.props.navigation.navigate('ModalScreen', {
            startScreen: this.constructor.name,
            setParentState: (state) => this.setState(state)
          })}
        />
        <Button
          title="Open ModalStack"
          onPress={() => this.props.navigation.navigate('ModalStack', {
            startScreen: this.constructor.name,
            setParentState: (state) => this.setState(state)
          })}
        />
      </View>
    )
  }
}

class TabB extends TabA {}
class TabC extends TabA {}

class ModalScreen extends React.Component {
  render () {
    const {
      startScreen,
      setParentState
    } = this.props.navigation.state.params
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text style={{ fontSize: 20 }}>{this.constructor.name}</Text>
        <Button
          title="Close"
          onPress={() => {
            setParentState({
              startScreen,
              returnScreen: this.constructor.name
            })
            this.props.navigation.goBack()
          }}
        />
      </View>
    )
  }
}


const DismissableStackNavigator = (routes, options) => {
  const StackNav = StackNavigator(routes, options)

  return class DismissableStackNav extends React.Component {
    static router = StackNav.router

    render () {
      const { state, goBack } = this.props.navigation
      const screenProps = {
        ...this.props.screenProps,
        dismissStackNav: () => goBack(state.key)
      }
      return (
        <StackNav
          screenProps={screenProps}
          navigation={this.props.navigation}
        />
      )
    }
  }
}

class ModalStackScreen extends React.Component {
  render () {
    const screenNumber = this.props.navigation.state.params && this.props.navigation.state.params.screenNumber || 0
    const {
      startScreen,
      setParentState
    } = this.props.navigation.state.params
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text style={{ fontSize: 20 }}>{this.constructor.name + screenNumber}</Text>
        <View style={{
          flexDirection: 'row',
          justifyContent: 'space-between'
        }}>
          <Button
            title={screenNumber === 0 ? "Close" : "Back"}
            onPress={() => this.props.navigation.goBack(null)}
          />
          <Button
            title="Save"
            onPress={() => {
              setParentState({
                startScreen,
                returnScreen: this.constructor.name + screenNumber
              })
              this.props.screenProps.dismissStackNav()
            }}
          />
          <Button
            title="Next"
            onPress={() => this.props.navigation.navigate('ModalStackScreen', {
              screenNumber: screenNumber + 1,
              startScreen,
              setParentState
            })}
          />
        </View>
      </View>
    )
  }
}

const TabNav = TabNavigator(
  {
    TabA: {
      screen: TabA
    },
    TabB: {
      screen: TabB
    },
    TabC: {
      screen: TabC
    }
  }
)

const ModalStack = DismissableStackNavigator(
  {
    ModalStackScreen: {
      screen: ModalStackScreen
    }
  },
  {
    headerMode: 'none'
  }
)

const RootStack = StackNavigator(
  {
    Main: {
      screen: TabNav,
    },
    ModalScreen: {
      screen: ModalScreen,
    },
    ModalStack: {
      screen: ModalStack
    }
  },
  {
    mode: 'modal',
    headerMode: 'none'
  }
)

class App extends React.Component {
  render () {
    return <RootStack />
  }
}

AppRegistry.registerComponent('HelloWorld', () => App)

Previous Answer

This solution is a sledgehammer. It causes the screen of the default tab in the TabNavigator to unmount and then mount again. If the Screen a tab launching the Modal with the StackNavigator passes some callbacks to update it's state, these callbacks will be called when the Screen is unmounted.

The solution was to add key: null to the reset object:

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

I was tipped off by this comment.

(FYI - I got here via your comment asking for help.)

查看更多
登录 后发表回答