如何关闭其中包含多个屏幕的 React Navigation 模式

Posted

技术标签:

【中文标题】如何关闭其中包含多个屏幕的 React Navigation 模式【英文标题】:How to close a React Navigation modal with multiple screens in it 【发布时间】:2018-09-23 01:35:01 【问题描述】:

我在 React Native 应用程序中使用 https://reactnavigation.org/ 进行导航,其中一个选项卡导航器作为主堆栈,一个包含两个屏幕的模式(用于登录和配置应用程序)。

我一辈子都想不出如何从第二个屏幕关闭模式 (SelectItems)。从模式中的第一个屏幕,我可以用navigation.goBack() 关闭它。

两个模态屏幕都需要一个关闭按钮。有没有办法返回到用户所在的任何选项卡?

提前感谢您的帮助。

const Tabs = TabNavigator(
  
    Search:  screen: Search ,
    Settings:  screen: Settings 
  
);

// modal with two screens
const Setup = StackNavigator(
  
    Login: 
      screen: Login
    ,
    SelectItems: 
      screen: SelectItems
    
  ,
  
    initialRouteName: 'Login'
  
);

const RootStack = StackNavigator(
  
    Main: 
      screen: Tabs
    ,
    Setup: 
      screen: Setup
    
  ,
  
    mode: 'modal',
    headerMode: 'none'
  
);

【问题讨论】:

【参考方案1】:

我找到了解决方案,但并不完美。

您可以使用 popToTop 将返回到堆栈的第一个场景,然后 goBack 将关闭模式。

navigation.popToTop();
navigation.goBack(null);

这样做的问题是它会再次挂载堆栈的第一个场景,所以请确保不要在 willMount 或 didMount 中使用setState。或者阻止它。

这就是我现在要使用的解决方案。我一直在寻找更好的解决方案。

【讨论】:

现在有更好的解决方案吗?【参考方案2】:

简单易用的 react-navigation 5.x 解决方案(getParent docs):

navigation.getParent()?.goBack();

之所以有效,是因为它抓取了导航器的父级,即模式和您想要关闭的内容。

注意:在旧版本的 5.x 中,这称为dangerouslyGetParent。这存在于较新的 5.x 版本中,但现在已弃用。如果 getParent 在您使用的 react-navigation 版本中不可用,请使用它。它实际上并不危险:来自 react-navigation 的文档:

该函数被称为危险GetParent 的原因是警告开发人员不要过度使用它,例如。获取 parent 的 parent 和其他难以遵循的模式。

【讨论】:

这解决了我的问题,非常感谢。我已经为此苦苦挣扎了至少2个小时。我遇到了一个问题,我会从堆栈上的父导航器推送屏幕,然后当我返回时,当前堆栈将导航回来,但最新推送的屏幕(来自父堆栈)将保持可见。快把我逼疯了。谢谢!!【参考方案3】:

如果你使用 react-navigation 4.x 有一个方法navigation.dismiss()。该方法关闭整个堆栈并返回父堆栈

https://reactnavigation.org/docs/4.x/navigation-prop/#dismiss

【讨论】:

【参考方案4】:

来自https://github.com/react-navigation/react-navigation/issues/686#issuecomment-342766039 的原始解决方案,针对 React Navigation 4 进行了更新:

创建DismissableStackNavigator

import React from 'react';
import  createStackNavigator  from 'react-navigation-stack';
export default function DismissableStackNavigator(routes, options) 

  const StackNav = createStackNavigator(routes, options);

  const DismissableStackNav = (navigation, screenProps) => 
    const  state, goBack  = navigation;
    const props = 
      ...screenProps,
      dismiss: () => goBack(state.key),
    ;

    return (
      <StackNav
        screenProps=props
        navigation=navigation
      />
    );
  

  DismissableStackNav.router = StackNav.router;
  return DismissableStackNav;
;

用法:

    创建堆栈:
// modal with two screens
const Setup = StackNavigator(
  
    Login: Login,
    SelectItems: SelectItems
  ,
  
    initialRouteName: 'Login'
    headerMode: 'none'
  
);
    在屏幕中调用 navigation.dismiss 以关闭模式堆栈。

【讨论】:

从 react-navigation@4 开始,我设法打电话给this.props.screenProps.dismiss()【参考方案5】:

我试图自己解决这个问题,我最终使用的解决方案是使用navigation.navigate()

例如this.props.navigation.navigate('name of screen you want to go');

希望这会有所帮助!

【讨论】:

谢谢 :) 我坚持使用已弃用的 React 导航,但我将其保存以备下次使用。 这个答案已经过时了,你需要在 2021 年使用钩子

以上是关于如何关闭其中包含多个屏幕的 React Navigation 模式的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React Native 中使 Tab.Navigation Screens 默认背景为白色?

如何使用 createStackNavigator 将 createBottomTabNavigator 添加到同一屏幕

在 Modal 中防止键盘关闭 React Native

React-Native 中的关闭重新加载页面

如何在 ios 上的 react-native-navigation(V1) 中添加后退按钮以关闭模式屏幕

如何在 React-Native 中获得键盘的高度?