Navigate to root screen from nested stack navigator

后端 未结 4 1141
迷失自我
迷失自我 2021-01-18 21:59

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 m

相关标签:
4条回答
  • 2021-01-18 22:03

    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);

    0 讨论(0)
  • 2021-01-18 22: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.

    0 讨论(0)
  • 2021-01-18 22:20

    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
    
    0 讨论(0)
  • 2021-01-18 22:22

    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

    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.)

    0 讨论(0)
提交回复
热议问题