【问题标题】:Resetting the navigation stack for the home screen (React Navigation and React Native)重置主屏幕的导航堆栈(React Navigation 和 React Native)
【发布时间】:2017-08-22 18:51:56
【问题描述】:

React Navigation 和 React Native 的导航有问题。这是关于重置导航并返回主屏幕。

我在 DrawerNavigator 内构建了一个 StackNavigator,并且主屏幕和其他屏幕之间的导航正常工作。但问题是,导航堆栈不断增长。我不确定如何从堆栈中删除屏幕。

例如,当从主屏幕进入设置屏幕,然后进入输入屏幕,最后再次进入主屏幕时,主屏幕在堆栈中出现两次。使用后退按钮,我不会退出应用程序,而是再次进入进入屏幕。

再次选择主页按钮时,重置堆栈会很棒,但我不知道该怎么做。 Here 有人试图帮助有类似问题的其他人,但该解决方案对我不起作用。

const Stack = StackNavigator({
  Home: {
    screen: Home
  },
  Entry: {
    screen: Entry
  },
  Settings: {
    screen: Settings
  }
})

export const Drawer = DrawerNavigator({
  Home: {
    screen: Stack
  }},
  {
    contentComponent: HamburgerMenu
  }
)

这是抽屉屏幕的一个简单示例

export default class HamburgerMenu extends Component {
  render () {
    return <ScrollView>
      <Icon.Button
        name={'home'}
        borderRadius={0}
        size={25}
        onPress={() => { this.props.navigation.navigate('Home')}}>
        <Text>{I18n.t('home')}</Text>
      </Icon.Button>

      <Icon.Button
        name={'settings'}
        borderRadius={0}
        size={25}
        onPress={() => { this.props.navigation.navigate('Settings')}}>
        <Text>{I18n.t('settings')}</Text>
      </Icon.Button>

      <Icon.Button
        name={'entry'}
        borderRadius={0}
        size={25}
        onPress={() => { this.props.navigation.navigate('Entry')}}>
        <Text>{I18n.t('entry')}</Text>
      </Icon.Button>
    </ScrollView>
  }
}

我希望你能帮助我。这是导航的重要组成部分,一个解决方案会很棒!

【问题讨论】:

    标签: javascript react-native navigation react-navigation


    【解决方案1】:

    反应导航 5.x , 6.x

    import { CommonActions } from '@react-navigation/native';
    
    navigation.dispatch(
      CommonActions.reset({
        index: 1,
        routes: [
          { name: 'Home' },
          {
            name: 'Profile',
            params: { user: 'jane' },
          },
        ],
      })
    );
    

    Snack中可用

    【讨论】:

    • 当我按下返回按钮时仍然无法正常工作
    • 这个答案应该是最重要的,我浪费了大约 30 分钟来寻找这个:祈祷
    • 这为 5.x 做这项工作
    • 适用于 React Navigation 5.10
    • 这对我有用,坦克!!!为什么只使用 CommonActions.reset 时不起作用?
    【解决方案2】:

    这就是我的做法:

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

    至少将“菜单”替换为“主页”。 您可能还想使 this.props.navigation 适应您的实现。

    在版本 > 2 中遵循以下内容:

    import { NavigationActions, StackActions } from 'react-navigation';
            const resetAction = StackActions.reset({
                    index: 0,
                    actions: [NavigationActions.navigate({ routeName: 'MainActivity' })],
                });
    
    this.props.navigation.dispatch(resetAction); 
    

    【讨论】:

    • 产生一个大多数 QA 会拒绝的令人讨厌的动画。
    • 这种情况下如何发送导航参数?
    • 为了避免讨厌的动画,我不得不根据this answer完全禁用所有转换的动画。
    • 工作得很好,但是你有没有内存泄漏?我知道在 Xamarin 上这样做不会释放堆栈并在孩子和父母之间导航会产生泄漏。这里也一样吗?
    • 我正在使用 react navigation v2 apis,reset api 已移至 StackActions (v2.reactnavigation.org/docs/en/stack-actions.html),但它对我不起作用,我正在尝试与链接中给出的相同方式
    【解决方案3】:

    我在使用 @react-navigation Bashirpour's Answer 时发现了这种方法。但是,在尝试已经在 props 中导航的功能组件时,这是编写重置堆栈操作的一种巧妙方法:

    props.navigation.reset({
         index: 0,
         routes: [{ name: 'Dashboard' }]
    })
    

    【讨论】:

    • 拯救我的一天尝试了许多不同的解决方案,但对于功能组件最佳解决方案。
    • 我想这是最好的方法。
    • 我清除了堆栈中路由的 componentWillUnmount 上的 timeInterval,这似乎不起作用。组件永远不会进入“卸载”状态?
    • 似乎适用于 Tab 导航,但是在屏幕之间切换时确实会产生明显的延迟。
    • 功能组件应该是navigation.reset而不是props.navigation.reset
    【解决方案4】:

    这是我的做法:

    import { NavigationActions } from 'react-navigation'
    
    this.props.navigation.dispatch(NavigationActions.reset({
        index: 0,
        key: null,
        actions: [NavigationActions.navigate({ routeName: 'ParentStackScreen' })]
    }))
    

    重要的部分是key: null

    这会在从子级导航器到父级导航器导航时擦除堆栈。

    如果您收到此错误,请执行此操作:

    对于动画,我使用

    // https://github.com/oblador/react-native-animatable
    import * as Animatable from 'react-native-animatable'
    

    我只是自己控制所有的动画。通过用&lt;Animatable.View&gt; 包裹它们,将它们放在您想要的任何 组件上。

    【讨论】:

    • 谢谢! key: null 是我所缺少的 :)
    • 上面显示的这段代码正在调度重置堆栈的操作,因此它会到达您想要触发的位置。例如,您可以将NavigationActions 导入到您的动作创建者文件中,并在某些动作通过时重置堆栈。
    【解决方案5】:

    对于最新版本的 react-navigation,您应该使用 StackActions 来重置堆栈,这是一段代码:

    // import the following
    import { NavigationActions, StackActions } from 'react-navigation'
    
    // at some point in your code
    resetStack = () => {
     this.props
       .navigation
       .dispatch(StackActions.reset({
         index: 0,
         actions: [
           NavigationActions.navigate({
             routeName: 'Home',
             params: { someParams: 'parameters goes here...' },
           }),
         ],
       }))
    }
    

    【讨论】:

    • 如果他想进入Settings屏幕怎么办?
    • @AvinashRaj 我不确定我是否听懂了你的问题,但如果我听懂了,只需将 routeName: 'Home' for routeName: 'Settings' 放在我发布的代码 sn-p 上。希望对你有帮助
    • 我通过添加另一个操作项使其工作。你知道如何设置抽屉项目焦点吗?因为通过这种方式导航后,焦点仍然在默认抽屉项上
    【解决方案6】:

    在 React 导航版本 5.x 中

    这个版本可以使用StackActions.replace

    import { StackActions } from '@react-navigation/native';
    
    
    navigation.dispatch(
        StackActions.replace('Home', { test: 'Test Params' })
    )
    

    完整示例:(Snack 提供)

    import * as React from 'react';
    import { View, Button, Text } from 'react-native';
    import { NavigationContainer, StackActions } from '@react-navigation/native';
    import { createStackNavigator } from '@react-navigation/stack';
    
    function SplashScreen({ navigation }) {
      return (
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
          <Text style={{fontSize:25,marginBottom:25}} >SPLASH SCREEN!</Text>
          <Button
            title="Replace (RESET) with Home"
            onPress={() =>
              navigation.dispatch(
                StackActions.replace('Home', { test: 'Test Params' })
              )
            }
          />
          <View style={{margin:10}}/>
          <Button
            title="Push Home on the stack"
            onPress={() =>
              navigation.dispatch(StackActions.push('Home', { test: 'Test Params' }))
            }
          />
        </View>
      );
    }
    
    function HomeScreen({ navigation, route }) {
      return (
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
          <Text style={{fontSize:25,marginBottom:25}}>Home Screen!</Text>
    
          <Text style={{margin:10}}>{route.params.test}</Text>
    
          <Button
            title="Push same screen on the stack"
            onPress={() => navigation.dispatch(StackActions.pop(1))} 
          /> 
          <View style={{margin:10}}/>
          <Button
            title="Pop one screen from stack" 
            onPress={() =>
              navigation.dispatch(StackActions.push('Home', { test: 'Test Params' }))
            }
          />
          <View style={{margin:10}}/>
          <Button
            title="Pop to top" 
            onPress={() => navigation.dispatch(StackActions.popToTop())}
          />
        </View>
      );
    }
    
    const Stack = createStackNavigator();
    
    export default function App() { 
      return (
        <NavigationContainer>
          <Stack.Navigator>
            <Stack.Screen name="Splash" component={SplashScreen} />
            <Stack.Screen name="Home" component={HomeScreen} />
          </Stack.Navigator>
        </NavigationContainer>
      );
    }
    
    

    【讨论】:

      【解决方案7】:

      要使用 Back,您需要找到与路径关联的唯一键。在导航减速器中,您可以搜索现有状态以使用该路径查找堆栈上的第一条路由,获取其键并将其传递给 Back。 Back 将导航到您提供的路径之前的屏幕。

        let key;
      
        if (action.payload) {
          // find first key associated with the route
          const route = action.payload;
      
          const routeObj = state.routes.find( (r) => r.routeName === route );
      
          if (routeObj) {
            key = { key: routeObj.key };
          }
        }
      
        return AppNavigator.router.getStateForAction( NavigationActions.back( key ), state );
      

      【讨论】:

        【解决方案8】:

        NavigationActions.reset() 似乎是更好的解决方案。我遇到的一个问题是选项卡按钮。即使我在组件中明确关闭它们,选项卡仍会显示。如果我使用 navigation.navigate() 而不是通过 reset() 执行此操作,它会正常工作。

        SomeComponentScreen.navigationOptions = {
          header: null
        };
        

        对我有用的解决方法是连续调用多个navigate 语句。

              navigation.goBack();   // this would pop current item in stack
              navigation.navigate({
                routeName: 'SomeOtherComponent'
              });
        

        【讨论】:

          【解决方案9】:

          答案是 createSwitchNavigator,它不会叠加您的导航。 在带有主屏幕/堆栈的 createSwitchNavigator 中添加您的身份验证屏幕/导航器。

          这样,当您从家导航登录时,不会保留堆栈。

          关于它的更多信息 https://reactnavigation.org/docs/en/auth-flow.htmlLoginStack

          【讨论】:

          • 找不到页面。
          • switchNavigator 仅在 react-navigation v4 之前使用,在 v5 中已弃用。
          【解决方案10】:

          弹出动作将您带回到堆栈中的上一个屏幕。 n 参数允许您指定要弹出多少个屏幕。

          n - number - 要弹回的屏幕数。

          从 'react-navigation' 导入 { StackActions };

          const popAction = StackActions.pop({ n: 1, });

          this.props.navigation.dispatch(popAction);

          【讨论】:

            【解决方案11】:

            只需混合上面给出的两种解决方案就可以了,基本上我们必须使用 StackActions 和 key: null。不使用 StackActions,它会抛出一些错误

            import { NavigationActions, StackActions } from 'react-navigation';
            const resetHandler = () => {
                    props.navigation.dispatch(StackActions.reset({
                        index: 0,
                        key: null,
                        actions: [NavigationActions.navigate({ routeName: 'PatientDetails' })]
                    }))
                };
            

            【讨论】:

              【解决方案12】:

              到目前为止一切正常:

              import { NavigationActions, StackActions } from 'react-navigation'
              
              resetStack = () => {
                      const navigateAction = NavigationActions.navigate({
                          routeName: 'Home',
              
                          params: {},
              
                          action: NavigationActions.navigate({ routeName: 'Home' }),
                      });
              
                      props.navigation.dispatch(navigateAction);
                  }
              

              在文档中找到:https://reactnavigation.org/docs/en/navigation-actions.html#reset

              【讨论】:

                【解决方案13】:

                在您的 StackNavigator 和 DrawerNavigator 中,您使用 Home 作为键,我认为它必须是唯一的,这就是它产生问题的原因。您能否尝试在 DrawerNavigator 中将 Home 替换为 Stack。

                希望这会有所帮助:)

                【讨论】:

                • 感谢您的回答,但遗憾的是没有任何改变。问题依然存在。
                • 我认为在你的情况下你应该使用 TabNavigator 而不是 StackNavigator。你能试试看吗?
                • 再次感谢您的回答,但我需要 StackNavigator。 TabNavigator 具有完全不同的行为并且没有标题栏。我需要重置 StackNavigator 的堆栈,或者导航器中可能没有双屏。
                • 您可以创建自定义标题,对于您的用例,我认为 TabNavigator 非常适合。
                • 我在这里看不到像 StackNavigator 这样的标题栏的任何可能性:reactnavigation.org/docs/navigators/tab 动画也是另一个。谢谢,但 TabNavigator 似乎不是解决方案。这只是某种解决方法。
                【解决方案14】:

                反应导航 6.x

                您可以使用popToTop() 操作来重置您的堆栈。 示例:

                import { StackActions } from '@react-navigation/native';
                
                navigation.dispatch(StackActions.popToTop());
                

                React-Navigation 文档:https://reactnavigation.org/docs/stack-actions/#poptotop

                【讨论】:

                  【解决方案15】:

                  这为我解决了这个问题(React Navigation 5.x

                  import {NavigationActions} from 'react-navigation';
                  
                  navigation.reset(
                    [NavigationActions.navigate({routeName: 'Profile'})],
                    0,
                  );
                  

                  【讨论】:

                    最近更新 更多