1import { NavigationProp, useNavigation } from '@react-navigation/native'; 2import { useCallback, useState, useEffect, useRef } from 'react'; 3 4import { useExpoRouter } from '../global-state/router-store'; 5 6type GenericNavigation = NavigationProp<ReactNavigation.RootParamList>; 7 8/** Returns a callback which is invoked when the navigation state has loaded. */ 9export function useLoadedNavigation() { 10 const { navigationRef } = useExpoRouter(); 11 const navigation = useNavigation(); 12 const isMounted = useRef(true); 13 const pending = useRef<((navigation: GenericNavigation) => void)[]>([]); 14 15 useEffect(() => { 16 isMounted.current = true; 17 return () => { 18 isMounted.current = false; 19 }; 20 }, []); 21 22 const flush = useCallback(() => { 23 if (isMounted.current) { 24 const pendingCallbacks = pending.current; 25 pending.current = []; 26 pendingCallbacks.forEach((callback) => { 27 callback(navigation); 28 }); 29 } 30 }, [navigation]); 31 32 useEffect(() => { 33 if (navigationRef.current) { 34 flush(); 35 } 36 }, [flush]); 37 38 const push = useCallback( 39 (fn: (navigation: GenericNavigation) => void) => { 40 pending.current.push(fn); 41 if (navigationRef.current) { 42 flush(); 43 } 44 }, 45 [flush] 46 ); 47 48 return push; 49} 50 51export function useOptionalNavigation(): GenericNavigation | null { 52 const [navigation, setNavigation] = useState<GenericNavigation | null>(null); 53 const loadNavigation = useLoadedNavigation(); 54 55 useEffect(() => { 56 loadNavigation((nav) => setNavigation(nav)); 57 }, []); 58 59 return navigation; 60} 61