【问题标题】:Navigate to root screen from nested stack navigator从嵌套堆栈导航器导航到根屏幕
【发布时间】:2017-06-28 11:54:32
【问题描述】:

我是新来的反应并试图自己学习它,我在将用户从嵌套的 stck 导航器屏幕导航回根屏幕时遇到问题。

这是我的一些课程:-

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

登录注册路由器:-

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

抽屉工具栏-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,
      },
  });

以上是我在我的应用程序中使用的堆栈架构,你可以看到我的主屏幕是登录屏幕,我在抽屉(侧面菜单)中确实有从应用程序注销的选项。我最想要的是,当用户单击注销时,他/她应该被重定向到登录屏幕。我已经对此进行了谷歌搜索并了解了两种方法,但这两种方法都不适合我,可能是我以错误的方式使用它们。所以我在这里寻求你的帮助。

这两种方法是:-

1)

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

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

这个问题对你来说可能看起来很傻,但我真的被困在这一点上,只是想知道我该如何解决这个问题。任何帮助将不胜感激!!!! 提前致谢。

【问题讨论】:

  • 试试这个 this.props.navigation.navigate('LoginScreen');
  • 它什么也没做。
  • 控制台props,查看props是否有导航或导航相关功能。

标签: javascript navigation react-navigation


【解决方案1】:

在尝试了几乎所有方法之后,我找到了适合我的解决方案:

  this.props.navigation.popToTop(); // go to the top of the stack
  this.props.navigation.goBack(null); // now show the root screen

【讨论】:

  • popToTop 是我想要的。谢谢
  • 对于 5.x,写nav.dispatch(StackActions.popToTop()) 两次(一个接一个)对我有用。
【解决方案2】:

Modal StackNavigator 包含 Dismissable StackNavigator

要求: react-navigation 版本:1.0.0

目标:App TabNavigator 导航到Screen 1Screen 2Screen N,然后直接返回到App TabNavigator。

导航层次结构:

  • 根导航器StackNavigator {mode: 'modal'}
    • 应用程序TabNavigator
      • TabA Screen
      • TabB Screen
      • TabC Screen
    • 模态屏幕Screen
    • 模态栈DismissableStackNavigator
      • 屏幕 1 ModalStackScreen
      • 屏幕 2 ModalStackScreen
      • 屏幕N ModalStackScreen

演示

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(或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)

上一个答案

这个解决方案是一个大锤。它会导致 TabNavigator 中默认选项卡的屏幕卸载,然后再次安装。如果使用 StackNavigator 启动 Modal 的 Screen a tab 传递了一些回调来更新它的状态,这些回调将在 Screen 卸载时被调用。

解决方案是将key: null 添加到重置对象:

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

I was tipped off by this comment.

(仅供参考 - 我是通过 your comment asking for help 到达这里的。)

【讨论】:

  • 根据你的sn-p,你的意思是NavigationActions.navigate({ routeName: 'App'})
  • @MarsonMao D'oh!是的。
  • @MarsonMao - 我已经用更好的解决方案更新了这个答案。
  • 不错!我也在使用这种方法!
  • 我的层次结构如下,StackNavigator->有,DrawerNavigator->有Tabnavigator,我做navigation.dispatch的时候。我收到如下错误-> ReactNativeJS: '登录时出错:', '{"line":161173,"column":69,"sourceURL":"localhost:8081/…"}'
【解决方案3】:

根据反应导航文档,您可以通过以下方式转到任何堆栈: 检查以下链接以获取更多详细信息 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. 如果你有一个配置文件堆栈,那么你也可以像这样检查下面的链接 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);

【讨论】:

    【解决方案4】:

    (React Navigation 5.x) 我遇到了像示例中那样有条件地渲染屏幕的问题 “https://reactnavigation.org/docs/en/auth-flow.html” 据我了解,这意味着堆栈导航器没有“渲染”,因此无法找到彼此。我所做的是在下面和注销页面中:

    navigation.replace('SplashScreen')
    

    我的逻辑是:SplashScreen(检查 AsyncStorage 令牌),

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

    在 StartScreen 中,只需导航到登录或注册,如果登录成功,您将返回应用程序。

    作为参考,

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

    导出默认 App 内容...

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

    我对此也很陌生,但它确实有效,所以如果其他人有更安全/更整洁/通用的解决方案,我也很想知道。

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 2021-12-03
      • 1970-01-01
      • 2022-01-20
      • 2018-06-09
      • 1970-01-01
      • 1970-01-01
      • 2018-03-26
      • 2018-03-17
      相关资源
      最近更新 更多