115

I've got a problem with the navigation of React Navigation and React Native. It is about resetting navigation and returning to the home screen.

I've build a StackNavigator inside of a DrawerNavigator, and the navigation between home screen and other screens is working. But the problem is, that the navigation stack grows and grows. I'm not sure how to remove a screen from the stack.

For example when going from the home screen to the settings screen, then to the entry screen and lastly again to the home screen, the home screen is twice in the stack. With the back button I do not get out of the app, but again to the entry screen.

When selecting the home button again a reset of the stack would be great, but I don't know how to do this. Here someone tried to help an other person with a similar problem, but the solution didn't work for me.

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

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

And this is a simple example of the drawer screen

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

I hope you can help me. This is an essential part of the navigation and a solution would be great!

Val
  • 21,938
  • 10
  • 68
  • 86
Daniel
  • 1,999
  • 4
  • 15
  • 27

15 Answers15

113

React Navigation 5.x , 6.x

import { CommonActions } from '@react-navigation/native';

navigation.dispatch(
  CommonActions.reset({
    index: 1,
    routes: [
      { name: 'Home' },
      {
        name: 'Profile',
        params: { user: 'jane' },
      },
    ],
  })
);

Available in Snack

Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
74

This is How I do it :

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

at least replace 'Menu' with 'Home'. You may also want to adapt this.props.navigation to your implementation.

In version > 2 follow this:

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

this.props.navigation.dispatch(resetAction); 
Nabeel K
  • 5,938
  • 11
  • 38
  • 68
Robin Dehu
  • 763
  • 5
  • 4
  • 33
    Produces a nasty animation that most QA would reject fyi. – Oliver Dixon Jul 19 '17 at 21:22
  • 1
    How to send Navigation Params in this case? – Ashish Aug 17 '17 at 22:41
  • 2
    In order to avoid the nasty animation, I had to completely disable animation for all transitions according to [this answer](https://stackoverflow.com/a/44332846/978369). – Kes115 Sep 10 '17 at 00:50
  • Work great, but did you get any memory leak? I know doing that on Xamarin don't release the stack and navigating between childs to parents produce leak. Is same here? – Leze Jan 03 '18 at 11:20
  • Where do you call this? I don't find any place to put this since DrawerNavigator manage to switch screens when we press the screen titles in the drawer. Should we use 'contentComponent' on DrawerNavigator? – Bright Lee Jan 11 '18 at 20:13
  • AH.. I get it. The guy who asked uses 'contentComponent'. – Bright Lee Jan 11 '18 at 20:15
  • I'm quite surprised that this is the accepted answer given the issue with the animation. Experiencing it too, but going to look at the links you guys suggest. – SwimmingG Mar 10 '18 at 12:59
  • I don't get it. I have seen this kind of question without a good answer many times. I can't even try this "solution" because I don't use contentComponent. I just try to open a view but the framework is totally in the way and crashes my app. It is easier to do this with assembly code, at least it is possible. – Niklas Rosencrantz Mar 26 '18 at 03:30
  • 3
    I am using react navigation v2 apis , reset api is moved to StackActions (https://v2.reactnavigation.org/docs/en/stack-actions.html) , but its not working for me , I am trying the same way as given in the link – Sadanand May 07 '18 at 07:36
44

I found this way to go while using @react-navigation Bashirpour's Answer. However, while trying out Functional components where you already have navigation in props here is a neat way to write reset Stack action:

props.navigation.reset({
     index: 0,
     routes: [{ name: 'Dashboard' }]
})
Safeer
  • 1,407
  • 1
  • 25
  • 29
  • I clear a timeInterval on componentWillUnmount of a route in the stack and this does not seem to be working. The component never goes to the "unmount" state? – user2078023 Oct 21 '20 at 14:38
  • 2
    Seems to work for Tab navigation, however, this does produce a noticeable lag when switching between screens. – augsteyer Oct 27 '20 at 21:11
  • It should be `navigation.reset` instead of `props.navigation.reset` for functional component. – cmcodes Nov 11 '20 at 07:17
  • You can also run this one off a navigation ref from the container initialization if you need to. Using a ref is generally discouraged unless you are working imperatively outside your component tree vs a using prop since it's not possible to support all the methods on whatever sub-navigator you have. But since you're purging state completely, the main container will have no problem with it as long as it answers true to `isReady()`. Cheers – Mike Hardy Dec 08 '21 at 05:37
27

Here is how I do it:

import { NavigationActions } from 'react-navigation'

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

The important part is key: null.

That wipes the stack while navigating from a child navigator to a parent navigator.

Do that if you get this error:

enter image description here

For animations, I use

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

I just control all the animations myself. Put them on any component you want by wrapping it with <Animatable.View>.

agm1984
  • 15,500
  • 6
  • 89
  • 113
  • This code shown above is dispatching the action that resets the stack, so it goes where you would like to trigger that. For example, you could import `NavigationActions` into your action creators file and reset the stack when certain actions come through. – agm1984 Mar 26 '18 at 22:28
20

For newest versions of react-navigation you should use StackActions for reset the stack, here's a piece of code:

// 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...' },
       }),
     ],
   }))
}
Gustavo Garcia
  • 521
  • 5
  • 5
  • what if he wants to go into `Settings` screen? – Avinash Raj Feb 11 '19 at 13:56
  • @AvinashRaj I'm not sure if I quiet understood your question, but if I did, just place routeName: 'Home' for routeName: 'Settings' on the code snippet I posted. Hope it helps – Gustavo Garcia Feb 12 '19 at 02:47
  • I made it to work by adding another action item. Do you know how to set drawer item focus? Because after navigating by this way, focus is still on the default drawer item – Avinash Raj Feb 12 '19 at 02:57
  • Hi, i have BottomNavigation, the reset: 0 replace my BottomNavigation, can u help? I dont want this, I want to reset from new screen after my bottom navigation – famfamfam Sep 26 '22 at 15:20
6

In React Navigation Versions 5.x

You can use StackActions.replace in this version

import { StackActions } from '@react-navigation/native';


navigation.dispatch(
    StackActions.replace('Home', { test: 'Test Params' })
)

Full Example: (Available in 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>
  );
}

Community
  • 1
  • 1
Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
3

To use Back, you need to find the unique key associated with the path. Inside your navigation reducer, you can search the existing state to find the first route on the stack using that path, grab its key & pass that to Back. Back will then navigate to the screen prior to the path you gave.

  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 );
peterorum
  • 1,401
  • 2
  • 15
  • 21
3

NavigationActions.reset() seems to be the preferable solution. One issue I ran into with it actions was the tab buttons. Tabs would still show even if I explicitly turned them off in component. If I used navigation.navigate() instead of doing this via reset() it would work fine.

SomeComponentScreen.navigationOptions = {
  header: null
};

A workaround for this annoyance that worked for me is to consecutively call multiple navigate statements.

      navigation.goBack();   // this would pop current item in stack
      navigation.navigate({
        routeName: 'SomeOtherComponent'
      });
Tim Hysniu
  • 1,446
  • 13
  • 24
2

Just mix the two solutions given above and this will work just fine, basically we have to use StackActions and key: null. Without using StackActions, it was throwing some error

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

The Answer is createSwitchNavigator, it those not stack up your navigation. Add your auth screen/navigator in a createSwitchNavigator with the home screen/stack.

With that, when you navigate from home to log in, the stacks are not kept.

For more on it https://reactnavigation.org/docs/en/auth-flow.htmlLoginStack

Nelson Bassey
  • 71
  • 1
  • 5
1

The pop action takes you back to a previous screen in the stack. The n param allows you to specify how many screens to pop back by.

n - number - The number of screens to pop back by.

import { StackActions } from 'react-navigation';

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

this.props.navigation.dispatch(popAction);

1

This works fine as of now:

import { NavigationActions, StackActions } from 'react-navigation'

resetStack = () => {
        const navigateAction = NavigationActions.navigate({
            routeName: 'Home',

            params: {},

            action: NavigationActions.navigate({ routeName: 'Home' }),
        });

        props.navigation.dispatch(navigateAction);
    }

Found here in the docs: https://reactnavigation.org/docs/en/navigation-actions.html#reset

Gvs Akhil
  • 2,165
  • 2
  • 16
  • 33
1

React Navigation 6.x

You can use popToTop() action to reset your stack. example:

import { StackActions } from '@react-navigation/native';

navigation.dispatch(StackActions.popToTop());

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

Ali Radmanesh
  • 2,248
  • 22
  • 26
1

This fixed the issue for me (React Navigation 5.x)

import {NavigationActions} from 'react-navigation';

navigation.reset(
  [NavigationActions.navigate({routeName: 'Profile'})],
  0,
);
Saran Raj
  • 365
  • 5
  • 11
0

In your StackNavigator and DrawerNavigator you have used Home as a key, and i think it has to be unique and that's why its creating the problem. Can you please try replacing Home with Stack inside your DrawerNavigator.

Hope this will help :)

  • Thanks for the answer, but unfortunately nothing has changed. The problem is still present. – Daniel Mar 29 '17 at 13:51
  • I think in your case you should use TabNavigator instead of StackNavigator. can you please try and check. – Vijay Suryawanshi Mar 29 '17 at 14:15
  • Thanks again for the answer, but I need the StackNavigator. The TabNavigator has a completely different behavior and no title bar. I need a reset of the stack of the StackNavigator, or the possibility to have no double screens in the navigator. – Daniel Mar 29 '17 at 17:13
  • You can create your custom header, and for your use case i think TabNavigator is perfect fit. – Vijay Suryawanshi Mar 30 '17 at 05:45
  • I don't see here any possibilities for a header bar like on the StackNavigator: https://reactnavigation.org/docs/navigators/tab The animation is also an other one. Thanks, but the TabNavigator doesn't seem to be the solution. This would be only some kind of work around. – Daniel Mar 30 '17 at 07:23