28

I'm using https://reactnavigation.org/ for navigation in a React Native app with a tab navigator as the main stack and a modal with two screens in it (for logging in and configuring the app).

I can't for the life of me figure out how to close the modal from the second screen (SelectItems). From the first screen in the modal I can close it with navigation.goBack().

Both modal screens need a close button. Is there a way to just return back to whatever tab the user was on?

Thanks in advance for any help.

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'
  }
);
Alex Dunae
  • 1,290
  • 3
  • 17
  • 28

7 Answers7

28

I found a solution but it isn't perfect.

You can use the popToTop which will go back to the first Scene of your stack and than the goBack will close the modal.

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

The problem with that is that it will mount again the first scene of the stack, so be sure you dont use setState in you willMount or didMount. Or prevent it.

That's the solution i'm going with for now. I keep looking for a better solution.

Alexandre Rivest
  • 694
  • 5
  • 14
26

Simple and easy solution for react-navigation 5.x (getParent docs):

navigation.getParent()?.goBack();

This works because it grabs the navigator's parent, which is the modal and what you want to dismiss.

NOTE: In older versions of 5.x this was called dangerouslyGetParent. That exists in newer 5.x versions, but is now deprecated. Use that if getParent isn't available in the version of react-navigation that you're using. It isn't actually dangerous: From react-navigation's documentation:

Reason why the function is called dangerouslyGetParent is to warn developers against overusing it to eg. get parent of parent and other hard-to-follow patterns.

stuckj
  • 977
  • 1
  • 13
  • 24
SamB
  • 2,621
  • 4
  • 34
  • 39
  • This solved my issue, thank you so so much. I've been struggling with this for at least 2 hours. I was running into an issue where I would push a screen from a parent navigator on the stack, then when I went back, the current stack would nav back but the latest pushed screen (from the parent stack) would stay visible. Was driving me crazy. Thank you!! – nhuesmann Feb 26 '22 at 00:38
  • Solved my issue as well! My stack was a wizard-like form, in which each step is a screen under a stack navigator. When finishing the whole thing or when canelling, I just needed to get rid of the whole navigator, so this exactly what I needed. – Silas Pedrosa Mar 29 '23 at 21:44
8

This was my solution with v6 in 2022. It closes the modal and navigates away without any weird behaviors (at least in my case).

onPress = () => {
    navigation.goBack(); // <-- this fixed it
    navigation.navigate("SomeScreen", { id: 123});
}
JCraine
  • 1,159
  • 2
  • 20
  • 38
1

If you are using Stack Navigation you can always move around in the navigation stack using navigation.pop(). For instance, if you want to close two open modals you can call the pop function with parameter value 2:

navigation.pop(2);
J.C. Gras
  • 4,934
  • 1
  • 37
  • 44
0

If you use react-navigation 4.x there is a method navigation.dismiss(). The method dismisses the entire stack and return to the parent stack

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

alx
  • 74
  • 3
-1

Original solution from https://github.com/react-navigation/react-navigation/issues/686#issuecomment-342766039, updated for React Navigation 4:

Create a 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;
};

Usage:

  1. Creating your stack:
// modal with two screens
const Setup = StackNavigator(
  {
    Login: Login,
    SelectItems: SelectItems
  },
  {
    initialRouteName: 'Login'
    headerMode: 'none'
  }
);
  1. Call navigation.dismiss in your screens to close the modal stack.
Shridhar Gupta
  • 914
  • 7
  • 11
-4

I was trying to figure this myself and the solution I ended up using was to use navigation.navigate()

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

Hope this helps!

Jonathan Perez
  • 111
  • 1
  • 11