Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1x 1x 1x 7x 7x 7x 7x 5x 7x 7x 1x 1x 1x | import { useEffect, useLayoutEffect } from "react";
import { BackHandler, Platform } from "react-native";
import {
NavigationProp,
ParamListBase,
usePreventRemove,
} from "@react-navigation/native";
type Options = {
// When true, skips the gestureEnabled setOptions call. Use this when
// gestureEnabled:false is already set statically in the navigator config so
// the dynamic setOptions doesn't accidentally re-enable the gesture.
skipGestureHandling?: boolean;
navigation?: NavigationProp<ParamListBase>;
};
export const useBlockBackNavigation = (
isSubmitting: boolean,
{ skipGestureHandling = false, navigation }: Options = {},
) => {
// usePreventRemove is the correct way to block back navigation in native-stack.
// The beforeRemove + e.preventDefault() approach is NOT supported in native-stack
// on iOS — the screen gets removed natively before JS can cancel it.
usePreventRemove(isSubmitting, () => {});
// Disable the swipe gesture dynamically. Skipped when the navigator already
// sets gestureEnabled:false statically — setOptions would otherwise override
// the static option back to true when isSubmitting is false.
useLayoutEffect(() => {
if (skipGestureHandling || !navigation) return;
navigation.setOptions({ gestureEnabled: !isSubmitting });
}, [navigation, isSubmitting, skipGestureHandling]);
// Block Android hardware back button
useEffect(() => {
if (Platform.OS !== "android" || !isSubmitting) return;
const subscription = BackHandler.addEventListener(
"hardwareBackPress",
() => true,
);
return () => subscription.remove();
}, [isSubmitting]);
};
|