Skip to content

Instantly share code, notes, and snippets.

@ChlorUpload
Created February 11, 2022 16:06
Show Gist options
  • Save ChlorUpload/6e9d255d2ca617448c37e52e9fdd1bdd to your computer and use it in GitHub Desktop.
Save ChlorUpload/6e9d255d2ca617448c37e52e9fdd1bdd to your computer and use it in GitHub Desktop.
react-navigation extension custom hook that enables a certain route to exit the app when back button is pressed twice.
import { NavigationProp, useNavigation } from '@react-navigation/native';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
BackHandler,
AppState,
AppStateStatus,
Platform,
ToastAndroid,
} from 'react-native';
const TOLERATION_TIME = 2000;
export function useDoubleBackExit() {
/**
* enable conditions
*/
const [active, setActive] = useState(false);
const [focused, setFocused] = useState(false);
/**
* app state active
*/
const handleAppState = useCallback(
(nextAppState: AppStateStatus) => {
setActive(nextAppState === 'active');
},
[setActive],
);
useEffect(() => {
setActive(AppState.currentState === 'active');
const subscription = AppState.addEventListener('change', handleAppState);
return () => {
subscription.remove();
};
}, [handleAppState]);
/**
* navigation focused
*/
const navigation = useNavigation();
const handleFocusNavigation = useCallback(() => {
setFocused(true);
}, [setFocused]);
const handleBlurNavigation = useCallback(() => {
setFocused(false);
}, [setFocused]);
useEffect(() => {
setFocused(navigation.isFocused());
navigation.addListener('focus', handleFocusNavigation);
navigation.addListener('blur', handleBlurNavigation);
return () => {
navigation.removeListener('focus', handleFocusNavigation);
navigation.removeListener('blur', handleBlurNavigation);
};
}, [handleFocusNavigation, handleBlurNavigation]);
const enabled = useMemo(() => active && focused, [active, focused]);
/**
* back handler
*/
const backPressed = useRef<number | null>(null);
const handleBack = useCallback(() => {
const current = Date.now();
if (
backPressed.current !== null &&
current - backPressed.current < TOLERATION_TIME
) {
BackHandler.exitApp();
backPressed.current = null;
} else {
if (Platform.OS === 'android') {
ToastAndroid.show('한 번 더 누르시면 종료됩니다.', ToastAndroid.SHORT);
}
}
backPressed.current = current;
return true;
}, []);
/**
* back handler registration
*/
useEffect(() => {
if (enabled) {
BackHandler.addEventListener('hardwareBackPress', handleBack);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBack);
backPressed.current = null;
};
}
}, [handleBack, enabled]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment