Search code examples
react-nativeexporeact-navigationstack-navigator

Prevent default back navigation when using expo-router


I'm currently using expo and expo-router for the first time and have a question about the default back navigation. What I mean by that is for example swiping from the left edge to the middle of the screen on Google Pixel. This will trigger a back navigation on my Stack navigator.

In my previous project with React Navtive CLI and React Navigation I could prevent that by adding a event listener to the "beforeRemove" event of the navigation prop.

How can I achieve this with expo-router? I followed their instruction to buid a CustomStack navigator and was hoping I can access "navigation" that way. My code looks basically like this:

CustomStack.tsx

import { createStackNavigator, StackNavigationOptions } from "@react-navigation/stack";
import { withLayoutContext } from "expo-router";

const { Navigator } = createStackNavigator();

export const CustomStack = withLayoutContext<StackNavigationOptions, typeof Navigator>(Navigator);

_layout.tsx

import { Stack } from "expo-router";
import { CustomStack } from "./CustomStack";

export default function RootLayout() {
return (
    <CustomStack>
        <Stack.Screen name="Home" />
        <Stack.Screen name="About" />
// ...
    </CustomStack>
  );
}

About.tsx

import type { StackScreenProps } from "@react-navigation/stack";
import { useEffect } from 'react';

export default function About({ navigation }: StackScreenProps<{}>) {

useEffect(() => {
   navigation.addListener('beforeRemove', (e) => {
        e.preventDefault();
        Alert.alert(
          'Changes might be lost',
          'Really want to go back?',
          [
            { text: "Cancel", style: 'cancel', onPress: () => { } },
            {
              text: "Yes",
              style: 'destructive',
              onPress: () => navigation.dispatch(e.data.action),
            },
          ]
        );
      };
    });
  }, [navigation]);

In my RN CLI app without TypeScript this useEffect in About.jsx works. Did I maybe mess up the types? I'm using TypeScript with RN for the first time and followed this documentation.

I really like the approach of expo-router that defines my navigation routes based on my files as well as the possibility to add layout files to my folders. So it would be amazing if someone could explain how to prevent the default back navigation while still being able to use expo-router.

Thanks for your help,
Thomas

I tried to use the navigation property to attach a event and prevent the default back navigation. I created a CustomStack navigator and imported all of the types according to the documentations. I was expecting that I can access the navigation property in my functional component and add event listener to it. The property however is undefined.


Solution

  • There is no need to use custom stack for this. The solution is way simpler because you only need to useNavigation from expo and not the react-native one like you did.

    So you can use expo-router stack and update your About component like this :

        import { useNavigation } from 'expo-router';
        import { useEffect } from 'react';
        
        export default function About() {
    
            // Navigation
            const navigation = useNavigation();
    
            // Effect
            useEffect(() => { 
                navigation.addListener('beforeRemove', (e) => {
                    e.preventDefault();
                    console.log('onback');
                    // Do your stuff here
                    navigation.dispatch(e.data.action);
                });
            }, []);
    
        }
    

    Hope this would be helpful, the expo-router documentation is not complete for now.

    Keep in mind that you would manage the listener to prevent unexpected calls of the listener with removeListener for example.