The idea is the user should not be able to navigate back
to any of the order screens if they use the hamburger menu to navigate to other screens while on any of the order screens.
Given the code…
const handleNavigation = (route: string) => {
const routes = navigation.getState().routes;
console.log('routes before:', routes);
const orderStartIndex = routes.findIndex(route => route.name === navScreens.orderStart.route);
console.log('orderStartIndex:', orderStartIndex);
if (orderStartIndex > -1) {
navigation.dispatch(StackActions.replace(navScreens.orderStart.route, { params: {} }));
// navigation.getState().routes.splice(orderStartIndex, 1);
}
console.log('routes after:', navigation.getState().routes);
navigation.replace(route);
};
Expected results after clicking on the settings in the hamburger menu:
I’ve looked at several similar questions, but none give the answer to give these expected results. replace
won’t remove the screen in the stack. And splice
removes the screen, but also results in a key error crashing the app. pop
will only remove the latest screen(s), which would is problematic since the current screen is the hamburger screen and would not finish routing to the selection made.
Edit: adding code for routes and stacks
NavigationConductor.tsx
import React from 'react';
import { NavigationContainer, RouteProp } from '@react-navigation/native';
import { TransitionPresets, createStackNavigator } from '@react-navigation/stack';
import { default as Main } from './Main';
import { Hamburger, HamburgerMenu } from '@app/components';
import { navRoutesToTitles, navScreens } from '@app/utils';
import type { StackParamsList } from '@app/types';
const Stack = createStackNavigator<StackParamsList>();
function getStackHeaderOptions(route: RouteProp<StackParamsList, string>, navigation: any): any {
const routes = navigation.getState().routes;
const routeTitle =
routes[routes.length - 1].name === navScreens.hamburgerMenu.route
? navRoutesToTitles[routes[routes.length - 2].name]
: navRoutesToTitles[route.name];
const isHamburgerOpen = route.name === navScreens.hamburgerMenu.route;
return {
headerTitleAlign: 'center',
headerStyle: { backgroundColor: '#003069' },
headerRightContainerStyle: { paddingRight: 20 },
headerLeftContainerStyle: { paddingLeft: 20 },
headerTitleStyle: { color: 'hsla(0,0%,100%,.8)' },
headerTintColor: 'hsla(0,0%,100%,.8)',
title: routeTitle,
...TransitionPresets.ModalFadeTransition,
headerLeft: () => <Hamburger navigation={navigation} isOpen={isHamburgerOpen} />
};
}
export default function NavigationConductor() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName={navScreens.home.route}
screenOptions={({ route, navigation }) => getStackHeaderOptions(route, navigation)}
>
{Main(Stack)}
<Stack.Group>
<Stack.Screen
name={navScreens.hamburgerMenu.route}
component={HamburgerMenu}
options={{ presentation: 'transparentModal' }}
/>
</Stack.Group>
</Stack.Navigator>
</NavigationContainer>
);
}
Main.tsx
import React, { ReactNode } from 'react';
import { Home, Items, OrderComplete, OrderReview, OrderSelectItems, OrderStart, Settings } from '@app/screens';
import { navScreens } from '@app/utils';
import type { NavigationStack } from '@app/types';
export default function Main(Stack: NavigationStack): ReactNode {
return (
<Stack.Group>
<Stack.Screen name={navScreens.home.route} component={Home} />
<Stack.Screen name={navScreens.items.route} component={Items} />
<Stack.Screen name={navScreens.orderComplete.route} component={OrderComplete} />
<Stack.Screen name={navScreens.orderReview.route} component={OrderReview} />
<Stack.Screen name={navScreens.orderSelectItems.route} component={OrderSelectItems} />
<Stack.Screen name={navScreens.orderStart.route} component={OrderStart} />
<Stack.Screen name={navScreens.settings.route} component={Settings} />
</Stack.Group>
);
}
2
Answers
I’m not sure you’re doing it the right way. But to answer your question…
When you want to add a route to the top of the stack and navigate forward to it, use
navigation.push()
.When you only want to navigate forward to it, use
navigation.navigate()
. If the screen has already been added to the stack, it won’t add it again.If you wanted to reset the stack, use
navigation.reset()
.And finally, if you wanted to cancel the hardware back button, you can use
BackHandler
.I’d suggest more to use
navigation.navigate()
andBackHandler
, if you don’t want to change more your code.Now, I might give you a more clean way to achieve this…
It sounds like the user shall follow your steps, and so without being able to go back.
You might actually use
ScrollView
.Here is a complete example :
It will reset the stack and put new route in stack
import { CommonActions } from ‘@react-navigation/native’;