import React, { useMemo, useRef } from 'react'; import BottomSheetRoute from './BottomSheetRoute'; import { SheetActions } from '../actions'; import { useForceUpdate } from '../hooks/useForceUpdate'; import { useStableCallback } from '../hooks/useStableCallback'; import type { ParamListBase } from '@react-navigation/native'; import type { BottomSheetDescriptorMap, BottomSheetNavigationConfig, BottomSheetNavigationHelpers, } from '../types'; import type { BottomSheetNavigationState } from '../router'; type Props = BottomSheetNavigationConfig & { state: BottomSheetNavigationState; navigation: BottomSheetNavigationHelpers; descriptors: BottomSheetDescriptorMap; }; const BottomSheetNavigatorView = ({ descriptors, state, navigation, }: Props) => { //#region hooks const forceUpdate = useForceUpdate(); //#endregion //#region variables const descriptorsCache = useRef({}); const [firstKey, ...restKeys] = useMemo( () => state.routes.map((route) => route.key), [state.routes] ); /** * we cache all presented routes descriptor */ restKeys.forEach((key) => { descriptorsCache.current[key] = descriptors[key]; }); /** * we flag removed routes in our cache */ Object.keys(descriptorsCache.current) .filter((key) => !restKeys.includes(key)) .forEach((key) => { descriptorsCache.current[key].removing = true; }); //#endregion //#region callbacks const handleOnDismiss = useStableCallback((key: string, removed: boolean) => { delete descriptorsCache.current[key]; /** * if sheet was dismissed by navigation state, we only force re-render the view. * but if it was dismissed by user interaction, we dispatch pop action to navigation state. */ if (removed) { forceUpdate(); } else { navigation?.dispatch?.({ ...SheetActions.pop(), source: key, target: state.key, }); } }); //#endregion return ( <> {descriptors[firstKey].render()} {Object.keys(descriptorsCache.current).map((key) => ( ))} ); }; export default BottomSheetNavigatorView;