@react-navigation/core 8.0.0-alpha.4 → 8.0.0-alpha.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -14
- package/lib/module/BaseNavigationContainer.js +168 -87
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/ConsumedParamsContext.js +5 -0
- package/lib/module/ConsumedParamsContext.js.map +1 -0
- package/lib/module/DataLoading.js +129 -0
- package/lib/module/DataLoading.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +7 -10
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +54 -9
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +36 -11
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationRootContext.js +8 -0
- package/lib/module/NavigationRootContext.js.map +1 -0
- package/lib/module/NavigationStateContext.js +3 -0
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/PreventRemoveContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +40 -31
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +12 -42
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +219 -67
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/StaticTreeContext.js +5 -0
- package/lib/module/StaticTreeContext.js.map +1 -0
- package/lib/module/createNavigationContainerRef.js +7 -9
- package/lib/module/createNavigationContainerRef.js.map +1 -1
- package/lib/module/createNavigatorFactory.js +27 -5
- package/lib/module/createNavigatorFactory.js.map +1 -1
- package/lib/module/findFocusedRoute.js +7 -4
- package/lib/module/findFocusedRoute.js.map +1 -1
- package/lib/module/getActionFromState.js +45 -20
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getPathFromState.js +204 -94
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +61 -14
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +608 -272
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +23 -0
- package/lib/module/getStateFromRouteParams.js.map +1 -0
- package/lib/module/index.js +7 -6
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +2 -0
- package/lib/module/internal.js.map +1 -0
- package/lib/module/isRecordEqual.js +1 -1
- package/lib/module/isRecordEqual.js.map +1 -1
- package/lib/module/queryString.js +71 -0
- package/lib/module/queryString.js.map +1 -0
- package/lib/module/theming/useTheme.js +1 -1
- package/lib/module/theming/useTheme.js.map +1 -1
- package/lib/module/types.js +35 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +65 -25
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useEventEmitter.js +48 -33
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useFocusEffect.js +4 -2
- package/lib/module/useFocusEffect.js.map +1 -1
- package/lib/module/useFocusEvents.js +15 -5
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +3 -3
- package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
- package/lib/module/useIsFocused.js +8 -12
- package/lib/module/useIsFocused.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +5 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useLazyValue.js.map +1 -1
- package/lib/module/useNavigation.js +4 -17
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +244 -147
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +92 -89
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +22 -29
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationIndependentTree.js +1 -1
- package/lib/module/useNavigationIndependentTree.js.map +1 -1
- package/lib/module/useNavigationState.js +158 -46
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +58 -11
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetNavigation.js +26 -0
- package/lib/module/useOnGetNavigation.js.map +1 -0
- package/lib/module/useOnGetState.js +7 -4
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +40 -31
- package/lib/module/useOnPreventRemove.js.map +1 -1
- package/lib/module/useOnRouteFocus.js +2 -2
- package/lib/module/useOnRouteFocus.js.map +1 -1
- package/lib/module/useOptionsGetters.js +34 -24
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +11 -5
- package/lib/module/usePreventRemove.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +2 -2
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +3 -4
- package/lib/module/useRegisterNavigator.js.map +1 -1
- package/lib/module/useRoute.js +2 -0
- package/lib/module/useRoute.js.map +1 -1
- package/lib/module/useRouteCache.js +51 -35
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +12 -10
- package/lib/module/useScheduleUpdate.js.map +1 -1
- package/lib/module/useStateForPath.js +1 -1
- package/lib/module/useStateForPath.js.map +1 -1
- package/lib/module/useSyncState.js +37 -15
- package/lib/module/useSyncState.js.map +1 -1
- package/lib/module/validatePathConfig.js +50 -36
- package/lib/module/validatePathConfig.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/ConsumedParamsContext.d.ts +3 -0
- package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
- package/lib/typescript/src/DataLoading.d.ts +21 -0
- package/lib/typescript/src/DataLoading.d.ts.map +1 -0
- package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
- package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
- package/lib/typescript/src/Group.d.ts +1 -1
- package/lib/typescript/src/Group.d.ts.map +1 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts +22 -14
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationHelpersContext.d.ts +1 -1
- package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +21 -18
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationRootContext.d.ts +8 -0
- package/lib/typescript/src/NavigationRootContext.d.ts.map +1 -0
- package/lib/typescript/src/NavigationStateContext.d.ts +4 -3
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
- package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +5 -2
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/Screen.d.ts +1 -1
- package/lib/typescript/src/Screen.d.ts.map +1 -1
- package/lib/typescript/src/StaticContainer.d.ts +1 -1
- package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts +189 -111
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
- package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
- package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts +23 -5
- package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
- package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
- package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts +4 -4
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPathFromState.d.ts +3 -3
- package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPatternParts.d.ts +5 -2
- package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +4 -7
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
- package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +36 -33
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal.d.ts +3 -0
- package/lib/typescript/src/internal.d.ts.map +1 -0
- package/lib/typescript/src/isRecordEqual.d.ts.map +1 -1
- package/lib/typescript/src/queryString.d.ts +5 -0
- package/lib/typescript/src/queryString.d.ts.map +1 -0
- package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
- package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
- package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +265 -167
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useChildListeners.d.ts +3 -3
- package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +13 -11
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts +2 -2
- package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
- package/lib/typescript/src/useFocusEffect.d.ts.map +1 -1
- package/lib/typescript/src/useFocusEvents.d.ts +2 -2
- package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts.map +1 -1
- package/lib/typescript/src/useIsFocused.d.ts +4 -0
- package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts +4 -3
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useLazyValue.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts +4 -2
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +22 -63
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +6 -5
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +18 -58
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +19 -3
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnAction.d.ts +9 -9
- package/lib/typescript/src/useOnAction.d.ts.map +1 -1
- package/lib/typescript/src/useOnGetNavigation.d.ts +12 -0
- package/lib/typescript/src/useOnGetNavigation.d.ts.map +1 -0
- package/lib/typescript/src/useOnGetState.d.ts +1 -1
- package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
- package/lib/typescript/src/useOnPreventRemove.d.ts +5 -9
- package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
- package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
- package/lib/typescript/src/useOptionsGetters.d.ts +2 -4
- package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/useRegisterNavigator.d.ts.map +1 -1
- package/lib/typescript/src/useRoute.d.ts +7 -3
- package/lib/typescript/src/useRoute.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts +7 -12
- package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
- package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/lib/typescript/src/useStateForPath.d.ts +1 -1
- package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
- package/lib/typescript/src/useSyncState.d.ts +1 -0
- package/lib/typescript/src/useSyncState.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +79 -39
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +26 -22
- package/src/BaseNavigationContainer.tsx +468 -333
- package/src/ConsumedParamsContext.tsx +5 -0
- package/src/DataLoading.tsx +206 -0
- package/src/NavigationBuilderContext.tsx +44 -25
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +60 -12
- package/src/NavigationProvider.tsx +47 -20
- package/src/NavigationRootContext.tsx +11 -0
- package/src/NavigationStateContext.tsx +9 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +55 -56
- package/src/SceneView.tsx +14 -40
- package/src/StaticNavigation.tsx +715 -328
- package/src/StaticTreeContext.tsx +7 -0
- package/src/createNavigationContainerRef.tsx +12 -11
- package/src/createNavigatorFactory.tsx +92 -8
- package/src/findFocusedRoute.tsx +16 -16
- package/src/getActionFromState.tsx +87 -51
- package/src/getPathFromState.tsx +310 -134
- package/src/getPatternParts.tsx +98 -16
- package/src/getStateFromPath.tsx +971 -344
- package/src/getStateFromRouteParams.tsx +59 -0
- package/src/index.tsx +57 -6
- package/src/internal.tsx +2 -0
- package/src/isRecordEqual.tsx +3 -1
- package/src/queryString.ts +109 -0
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +799 -377
- package/src/useDescriptors.tsx +151 -43
- package/src/useEventEmitter.tsx +53 -39
- package/src/useFocusEffect.tsx +5 -2
- package/src/useFocusEvents.tsx +19 -8
- package/src/useFocusedListenersChildrenAdapter.tsx +3 -3
- package/src/useIsFocused.tsx +18 -21
- package/src/useKeyedChildListeners.tsx +5 -2
- package/src/useLazyValue.tsx +2 -2
- package/src/useNavigation.tsx +9 -26
- package/src/useNavigationBuilder.tsx +370 -201
- package/src/useNavigationCache.tsx +148 -123
- package/src/useNavigationHelpers.tsx +27 -37
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +207 -69
- package/src/useOnAction.tsx +92 -18
- package/src/useOnGetNavigation.tsx +30 -0
- package/src/useOnGetState.tsx +8 -4
- package/src/useOnPreventRemove.tsx +78 -43
- package/src/useOnRouteFocus.tsx +11 -15
- package/src/useOptionsGetters.tsx +41 -28
- package/src/usePreventRemove.tsx +13 -5
- package/src/usePreventRemoveContext.tsx +2 -2
- package/src/useRegisterNavigator.tsx +4 -4
- package/src/useRoute.tsx +20 -6
- package/src/useRouteCache.tsx +57 -35
- package/src/useScheduleUpdate.tsx +13 -11
- package/src/useStateForPath.tsx +1 -1
- package/src/useSyncState.tsx +39 -15
- package/src/utilities.tsx +151 -35
- package/src/validatePathConfig.tsx +86 -57
- package/lib/module/CurrentRenderContext.js +0 -10
- package/lib/module/CurrentRenderContext.js.map +0 -1
- package/lib/module/NavigationMetaContext.js +0 -15
- package/lib/module/NavigationMetaContext.js.map +0 -1
- package/lib/module/checkSerializable.js +0 -46
- package/lib/module/checkSerializable.js.map +0 -1
- package/lib/module/useComponent.js +0 -34
- package/lib/module/useComponent.js.map +0 -1
- package/lib/module/useCurrentRender.js +0 -19
- package/lib/module/useCurrentRender.js.map +0 -1
- package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
- package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
- package/lib/typescript/src/NavigationMetaContext.d.ts +0 -12
- package/lib/typescript/src/NavigationMetaContext.d.ts.map +0 -1
- package/lib/typescript/src/checkSerializable.d.ts +0 -10
- package/lib/typescript/src/checkSerializable.d.ts.map +0 -1
- package/lib/typescript/src/useComponent.d.ts +0 -7
- package/lib/typescript/src/useComponent.d.ts.map +0 -1
- package/lib/typescript/src/useCurrentRender.d.ts +0 -14
- package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
- package/src/CurrentRenderContext.tsx +0 -9
- package/src/NavigationMetaContext.tsx +0 -14
- package/src/checkSerializable.tsx +0 -74
- package/src/useComponent.tsx +0 -37
- package/src/useCurrentRender.tsx +0 -31
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import useLatestCallback from 'use-latest-callback';
|
|
4
|
-
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector';
|
|
5
3
|
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
RootNavigator,
|
|
10
|
-
} from './types';
|
|
11
|
-
import { useNavigation } from './useNavigation';
|
|
4
|
+
import type { NavigationListForNested, RootNavigator } from './types';
|
|
5
|
+
|
|
6
|
+
type NavigationStateEvent = 'update' | 'commit';
|
|
12
7
|
|
|
13
8
|
type NavigationStateListener = {
|
|
9
|
+
initialStateContext: React.Context<NavigationState<ParamListBase>>;
|
|
14
10
|
getState: () => NavigationState<ParamListBase>;
|
|
15
|
-
|
|
11
|
+
getSnapshot: () => NavigationState<ParamListBase>;
|
|
12
|
+
subscribe: (callback: (event: NavigationStateEvent) => void) => () => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type NavigationStateEntry = {
|
|
16
|
+
listener: NavigationStateListener;
|
|
17
|
+
state: NavigationState<ParamListBase>;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
type NavigationStateForNested<
|
|
@@ -35,8 +37,8 @@ type NavigationStateForNested<
|
|
|
35
37
|
export function useNavigationState<
|
|
36
38
|
const T,
|
|
37
39
|
const Navigator = RootNavigator,
|
|
38
|
-
const RouteName extends
|
|
39
|
-
keyof NavigationListForNested<Navigator
|
|
40
|
+
const RouteName extends keyof NavigationListForNested<Navigator> =
|
|
41
|
+
keyof NavigationListForNested<Navigator>,
|
|
40
42
|
>(
|
|
41
43
|
routeName: RouteName,
|
|
42
44
|
selector: (state: NavigationStateForNested<Navigator, RouteName>) => T
|
|
@@ -45,108 +47,244 @@ export function useNavigationState<T>(
|
|
|
45
47
|
selector: (state: NavigationState<ParamListBase>) => T
|
|
46
48
|
): T;
|
|
47
49
|
export function useNavigationState(...args: unknown[]): unknown {
|
|
48
|
-
|
|
49
|
-
stateListener: NavigationStateListener | undefined,
|
|
50
|
-
selector;
|
|
50
|
+
const selector = typeof args[0] === 'string' ? args[1] : args[0];
|
|
51
51
|
|
|
52
|
-
if (typeof
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
navigation = useNavigation(args[0]);
|
|
57
|
-
selector = args[1];
|
|
58
|
-
} else {
|
|
59
|
-
selector = args[0];
|
|
52
|
+
if (typeof selector !== 'function') {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`A selector function must be provided (got ${typeof selector}).`
|
|
55
|
+
);
|
|
60
56
|
}
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
// @ts-expect-error: the public overloads guarantee the selector's type, but
|
|
59
|
+
// the `unknown[]` implementation signature can't express it
|
|
60
|
+
const select: (state: NavigationState<ParamListBase>) => unknown = selector;
|
|
61
|
+
|
|
62
|
+
let listener: NavigationStateListener | undefined;
|
|
63
|
+
|
|
64
|
+
if (typeof args[0] === 'string') {
|
|
65
|
+
const name = args[0];
|
|
66
|
+
const listeners = React.use(NamedNavigationStateListenerListContext);
|
|
67
|
+
|
|
68
|
+
listener = listeners?.[name];
|
|
69
|
+
|
|
70
|
+
if (listener == null) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Couldn't find a navigator for the route '${name}' in any of the parent screens. Is your component inside the correct screen?`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
listener = React.use(NavigationStateListenerContext);
|
|
64
77
|
|
|
65
|
-
if (
|
|
78
|
+
if (listener == null) {
|
|
66
79
|
throw new Error(
|
|
67
80
|
"Couldn't get the navigation state. Is your component inside a navigator?"
|
|
68
81
|
);
|
|
69
82
|
}
|
|
70
83
|
}
|
|
71
84
|
|
|
72
|
-
const subscribe =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
const { getState, getSnapshot, subscribe } = listener;
|
|
86
|
+
|
|
87
|
+
const initialRef = React.useRef(true);
|
|
88
|
+
|
|
89
|
+
// We read the initial state from context on mount instead of using getState
|
|
90
|
+
// This ensures that we get proper state for the current render,
|
|
91
|
+
// even if the external store has been updated.
|
|
92
|
+
// We conditionally use `use` to avoid more unnecessary re-renders after first mount.
|
|
93
|
+
// The context subscription is removed on the next render, which can cause one extra render.
|
|
94
|
+
const initialState = initialRef.current
|
|
95
|
+
? React.use(listener.initialStateContext)
|
|
96
|
+
: undefined;
|
|
97
|
+
|
|
98
|
+
// We track the last committed reducer entry, navigation state, and selector,
|
|
99
|
+
// so we can check if an update changes the value the component last committed.
|
|
100
|
+
const committedRef = React.useRef<{
|
|
101
|
+
entry: NavigationStateEntry | null;
|
|
102
|
+
state: NavigationState<ParamListBase>;
|
|
103
|
+
select: (state: NavigationState<ParamListBase>) => unknown;
|
|
104
|
+
}>({ entry: null, state: initialState ?? getSnapshot(), select });
|
|
105
|
+
|
|
106
|
+
// The store can contain state from a transition that hasn't committed yet.
|
|
107
|
+
// Reading it during render can show state that doesn't match the navigator in that render.
|
|
108
|
+
// The reducer lets React process state in the same render lane as the navigator.
|
|
109
|
+
const [entry, dispatch] = React.useReducer(
|
|
110
|
+
(previous: NavigationStateEntry, event: NavigationStateEvent) => {
|
|
111
|
+
// Navigation state can change between the dispatch and the reducer running.
|
|
112
|
+
// Reading here ensures the processed event uses the state for that render.
|
|
113
|
+
const state = event === 'update' ? getState() : getSnapshot();
|
|
114
|
+
|
|
115
|
+
// If we're processing the same reducer entry as the last commit,
|
|
116
|
+
// we compare against the state last committed by the component.
|
|
117
|
+
// We keep the reducer entry to avoid re-renders for unchanged selections.
|
|
118
|
+
// This means the reducer entry can still hold older navigation state.
|
|
119
|
+
// If a parent causes another render,
|
|
120
|
+
// we use the latest snapshot so the selector doesn't read stale state.
|
|
121
|
+
// We leave the reducer entry unchanged to avoid an extra render.
|
|
122
|
+
// We save that snapshot in committedRef when the render commits,
|
|
123
|
+
// so later updates compare against the state we actually rendered,
|
|
124
|
+
// including when the selector changed.
|
|
125
|
+
// If the reducer entry is different, we use its own navigation state,
|
|
126
|
+
// so comparisons include updates already processed in the pending render.
|
|
127
|
+
const previousState =
|
|
128
|
+
previous === committedRef.current.entry
|
|
129
|
+
? committedRef.current.state
|
|
130
|
+
: previous.state;
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
previous.listener === listener &&
|
|
134
|
+
(previousState === state ||
|
|
135
|
+
(event === 'update' &&
|
|
136
|
+
Object.is(select(previousState), select(state))))
|
|
137
|
+
) {
|
|
138
|
+
return previous;
|
|
82
139
|
}
|
|
140
|
+
|
|
141
|
+
return { listener, state };
|
|
83
142
|
},
|
|
84
|
-
|
|
143
|
+
undefined,
|
|
144
|
+
() => ({ listener, state: initialState ?? getSnapshot() })
|
|
85
145
|
);
|
|
86
146
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
147
|
+
const state =
|
|
148
|
+
// A different listener means the state belongs to another navigator.
|
|
149
|
+
// This can happen when the passed route name changes.
|
|
150
|
+
entry.listener !== listener ||
|
|
151
|
+
// An entry that advanced past the last commit is at least as new as the snapshot.
|
|
152
|
+
// An entry that didn't advance while the committed state changed is older.
|
|
153
|
+
entry === committedRef.current.entry
|
|
154
|
+
? getSnapshot()
|
|
155
|
+
: entry.state;
|
|
90
156
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
157
|
+
React.useInsertionEffect(() => {
|
|
158
|
+
initialRef.current = false;
|
|
159
|
+
committedRef.current = { entry, state, select };
|
|
160
|
+
});
|
|
94
161
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
);
|
|
99
|
-
}
|
|
162
|
+
React.useLayoutEffect(() => {
|
|
163
|
+
const check = (event: NavigationStateEvent) => {
|
|
164
|
+
const { state, select } = committedRef.current;
|
|
100
165
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
166
|
+
// An 'update' event follows the latest state in the lane the update was made in.
|
|
167
|
+
// A 'commit' event syncs the reducer to the state committed by the navigator.
|
|
168
|
+
const target = event === 'update' ? getState() : getSnapshot();
|
|
169
|
+
|
|
170
|
+
if (state !== target && !Object.is(select(state), select(target))) {
|
|
171
|
+
dispatch(event);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const unsubscribe = subscribe(check);
|
|
176
|
+
|
|
177
|
+
// The reducer may not match the committed state when the subscription starts.
|
|
178
|
+
// This happens on mount during a transition or an update before subscribing.
|
|
179
|
+
check('commit');
|
|
180
|
+
|
|
181
|
+
return unsubscribe;
|
|
182
|
+
}, [getState, getSnapshot, subscribe]);
|
|
108
183
|
|
|
109
|
-
return
|
|
184
|
+
return select(state);
|
|
110
185
|
}
|
|
111
186
|
|
|
112
187
|
export function NavigationStateListenerProvider({
|
|
188
|
+
isSynced,
|
|
113
189
|
state,
|
|
190
|
+
getState,
|
|
191
|
+
subscribe,
|
|
114
192
|
children,
|
|
115
193
|
}: {
|
|
194
|
+
isSynced: boolean;
|
|
116
195
|
state: NavigationState<ParamListBase>;
|
|
196
|
+
getState: () => NavigationState<ParamListBase>;
|
|
197
|
+
subscribe: (callback: () => void) => () => void;
|
|
117
198
|
children: React.ReactNode;
|
|
118
199
|
}) {
|
|
119
|
-
const
|
|
200
|
+
const [InitialStateContext] = React.useState(() =>
|
|
201
|
+
React.createContext(state)
|
|
202
|
+
);
|
|
120
203
|
|
|
121
|
-
const
|
|
204
|
+
const [listeners] = React.useState(
|
|
205
|
+
() => new Set<(event: NavigationStateEvent) => void>()
|
|
206
|
+
);
|
|
122
207
|
|
|
123
|
-
|
|
124
|
-
listeners.
|
|
208
|
+
React.useLayoutEffect(() => {
|
|
209
|
+
listeners.forEach((listener) => listener('commit'));
|
|
210
|
+
}, [listeners, state]);
|
|
125
211
|
|
|
126
|
-
|
|
127
|
-
listeners.current = listeners.current.filter((cb) => cb !== callback);
|
|
128
|
-
};
|
|
129
|
-
});
|
|
212
|
+
const snapshotRef = React.useRef(state);
|
|
130
213
|
|
|
131
|
-
React.
|
|
132
|
-
|
|
214
|
+
React.useInsertionEffect(() => {
|
|
215
|
+
snapshotRef.current = state;
|
|
133
216
|
}, [state]);
|
|
134
217
|
|
|
218
|
+
// Route config or nested params can produce new state during render.
|
|
219
|
+
// If the scheduled update hasn't synced that state to the store yet,
|
|
220
|
+
// We need to expose the rendered state so consumers match the navigator.
|
|
221
|
+
// We keep this `undefined` for other scenarios, so the context isn't recreated.
|
|
222
|
+
const nextState = isSynced ? undefined : state;
|
|
223
|
+
|
|
135
224
|
const context = React.useMemo(
|
|
136
225
|
() => ({
|
|
226
|
+
initialStateContext: InitialStateContext,
|
|
137
227
|
getState,
|
|
138
|
-
|
|
228
|
+
getSnapshot: () => nextState ?? snapshotRef.current,
|
|
229
|
+
subscribe: (callback: (event: NavigationStateEvent) => void) => {
|
|
230
|
+
const unsubscribe = subscribe(() => callback('update'));
|
|
231
|
+
|
|
232
|
+
listeners.add(callback);
|
|
233
|
+
|
|
234
|
+
return () => {
|
|
235
|
+
listeners.delete(callback);
|
|
236
|
+
unsubscribe();
|
|
237
|
+
};
|
|
238
|
+
},
|
|
139
239
|
}),
|
|
140
|
-
[getState, subscribe]
|
|
240
|
+
[InitialStateContext, getState, listeners, nextState, subscribe]
|
|
141
241
|
);
|
|
142
242
|
|
|
143
243
|
return (
|
|
144
244
|
<NavigationStateListenerContext.Provider value={context}>
|
|
145
|
-
{
|
|
245
|
+
<InitialStateContext.Provider value={state}>
|
|
246
|
+
{children}
|
|
247
|
+
</InitialStateContext.Provider>
|
|
146
248
|
</NavigationStateListenerContext.Provider>
|
|
147
249
|
);
|
|
148
250
|
}
|
|
149
251
|
|
|
150
|
-
|
|
252
|
+
export function NamedNavigationStateListenerProvider({
|
|
253
|
+
name,
|
|
254
|
+
children,
|
|
255
|
+
}: {
|
|
256
|
+
name: string;
|
|
257
|
+
children: React.ReactNode;
|
|
258
|
+
}) {
|
|
259
|
+
const listener = React.use(NavigationStateListenerContext);
|
|
260
|
+
|
|
261
|
+
if (listener == null) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
"Couldn't find a navigation state listener. This is likely a bug in the navigator.\n\nIf you're using a custom navigator, make sure that the navigator content is wrapped by the 'render' function returned by 'useNavigationBuilder'."
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const parents = React.use(NamedNavigationStateListenerListContext);
|
|
268
|
+
|
|
269
|
+
const listeners = React.useMemo(
|
|
270
|
+
() => ({
|
|
271
|
+
...parents,
|
|
272
|
+
[name]: listener,
|
|
273
|
+
}),
|
|
274
|
+
[listener, name, parents]
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<NamedNavigationStateListenerListContext.Provider value={listeners}>
|
|
279
|
+
{children}
|
|
280
|
+
</NamedNavigationStateListenerListContext.Provider>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export const NavigationStateListenerContext = React.createContext<
|
|
151
285
|
NavigationStateListener | undefined
|
|
152
286
|
>(undefined);
|
|
287
|
+
|
|
288
|
+
export const NamedNavigationStateListenerListContext = React.createContext<
|
|
289
|
+
Record<string, NavigationStateListener> | undefined
|
|
290
|
+
>(undefined);
|
package/src/useOnAction.tsx
CHANGED
|
@@ -7,20 +7,23 @@ import type {
|
|
|
7
7
|
} from '@react-navigation/routers';
|
|
8
8
|
import * as React from 'react';
|
|
9
9
|
|
|
10
|
+
import { ConsumedParamsContext } from './ConsumedParamsContext';
|
|
11
|
+
import { getLoaderForStateChange } from './DataLoading';
|
|
10
12
|
import {
|
|
11
13
|
type ChildActionListener,
|
|
12
14
|
type ChildBeforeRemoveListener,
|
|
13
|
-
|
|
15
|
+
useNavigationBuilderContext,
|
|
14
16
|
} from './NavigationBuilderContext';
|
|
17
|
+
import { StaticTreeContext } from './StaticTreeContext';
|
|
15
18
|
import type { EventMapCore } from './types';
|
|
16
19
|
import type { NavigationEventEmitter } from './useEventEmitter';
|
|
17
20
|
import { shouldPreventRemove, useOnPreventRemove } from './useOnPreventRemove';
|
|
18
21
|
|
|
19
|
-
type Options = {
|
|
20
|
-
router: Router<
|
|
21
|
-
key?: string;
|
|
22
|
-
getState: () =>
|
|
23
|
-
setState: (state:
|
|
22
|
+
type Options<State extends NavigationState> = {
|
|
23
|
+
router: Router<State, NavigationAction>;
|
|
24
|
+
key?: string | undefined;
|
|
25
|
+
getState: () => State;
|
|
26
|
+
setState: (state: State | PartialState<State>) => void;
|
|
24
27
|
actionListeners: ChildActionListener[];
|
|
25
28
|
beforeRemoveListeners: Record<string, ChildBeforeRemoveListener | undefined>;
|
|
26
29
|
routerConfigOptions: RouterConfigOptions;
|
|
@@ -36,7 +39,7 @@ type Options = {
|
|
|
36
39
|
*
|
|
37
40
|
* When the action handler handles as action, it returns `true`, otherwise `false`.
|
|
38
41
|
*/
|
|
39
|
-
export function useOnAction({
|
|
42
|
+
export function useOnAction<State extends NavigationState>({
|
|
40
43
|
router,
|
|
41
44
|
getState,
|
|
42
45
|
setState,
|
|
@@ -45,18 +48,22 @@ export function useOnAction({
|
|
|
45
48
|
beforeRemoveListeners,
|
|
46
49
|
routerConfigOptions,
|
|
47
50
|
emitter,
|
|
48
|
-
}: Options) {
|
|
51
|
+
}: Options<State>) {
|
|
49
52
|
const {
|
|
50
53
|
onAction: onActionParent,
|
|
51
54
|
onRouteFocus: onRouteFocusParent,
|
|
52
55
|
addListener: addListenerParent,
|
|
53
56
|
onDispatchAction,
|
|
54
|
-
|
|
57
|
+
flushUpdates,
|
|
58
|
+
} = useNavigationBuilderContext();
|
|
59
|
+
|
|
60
|
+
const tree = React.use(StaticTreeContext);
|
|
61
|
+
const consumedParams = React.use(ConsumedParamsContext);
|
|
55
62
|
|
|
56
63
|
const routerConfigOptionsRef =
|
|
57
64
|
React.useRef<RouterConfigOptions>(routerConfigOptions);
|
|
58
65
|
|
|
59
|
-
React.
|
|
66
|
+
React.useInsertionEffect(() => {
|
|
60
67
|
routerConfigOptionsRef.current = routerConfigOptions;
|
|
61
68
|
});
|
|
62
69
|
|
|
@@ -65,6 +72,11 @@ export function useOnAction({
|
|
|
65
72
|
action: NavigationAction,
|
|
66
73
|
visitedNavigators: Set<string> = new Set<string>()
|
|
67
74
|
) => {
|
|
75
|
+
// Apply any pending state updates scheduled during render before handling the action
|
|
76
|
+
// Otherwise the action will be handled with an outdated state,
|
|
77
|
+
// and the pending updates will overwrite the changes from the action
|
|
78
|
+
flushUpdates();
|
|
79
|
+
|
|
68
80
|
const state = getState();
|
|
69
81
|
|
|
70
82
|
// Since actions can bubble both up and down, they could come to the same navigator again
|
|
@@ -83,13 +95,23 @@ export function useOnAction({
|
|
|
83
95
|
);
|
|
84
96
|
|
|
85
97
|
// If a target is specified and set to current navigator, the action shouldn't bubble
|
|
86
|
-
// So
|
|
87
|
-
result
|
|
88
|
-
|
|
98
|
+
// So we immediately return `false` to mark it as unhandled
|
|
99
|
+
if (result === null && action.target === state.key) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
89
102
|
|
|
90
|
-
if (result !== null) {
|
|
91
|
-
|
|
103
|
+
if (result !== null && result.stale !== false) {
|
|
104
|
+
// Some actions (e.g. `RESET`) may return a stale state from the router
|
|
105
|
+
// We rehydrate it before storing so the stored state is always usable
|
|
106
|
+
// Otherwise anything reading the state before the next render
|
|
107
|
+
// (e.g. another dispatch immediately after) would get an outdated state
|
|
108
|
+
result = router.getRehydratedState(
|
|
109
|
+
result,
|
|
110
|
+
routerConfigOptionsRef.current
|
|
111
|
+
);
|
|
112
|
+
}
|
|
92
113
|
|
|
114
|
+
if (result !== null) {
|
|
93
115
|
if (state !== result) {
|
|
94
116
|
const isPrevented = shouldPreventRemove(
|
|
95
117
|
emitter,
|
|
@@ -100,10 +122,34 @@ export function useOnAction({
|
|
|
100
122
|
);
|
|
101
123
|
|
|
102
124
|
if (isPrevented) {
|
|
125
|
+
onDispatchAction(action, true);
|
|
126
|
+
|
|
103
127
|
return true;
|
|
104
128
|
}
|
|
105
129
|
|
|
130
|
+
if (getState() !== state) {
|
|
131
|
+
// Listeners for 'beforeRemove' may dispatch actions that change the state
|
|
132
|
+
// Then the result we have is outdated and would overwrite those changes
|
|
133
|
+
// So we handle the action again to calculate the result with the latest state
|
|
134
|
+
return onAction(action, new Set<string>());
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
onDispatchAction(action, false);
|
|
138
|
+
|
|
139
|
+
if (tree) {
|
|
140
|
+
const loader = getLoaderForStateChange(
|
|
141
|
+
tree,
|
|
142
|
+
result,
|
|
143
|
+
state,
|
|
144
|
+
consumedParams
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
loader?.();
|
|
148
|
+
}
|
|
149
|
+
|
|
106
150
|
setState(result);
|
|
151
|
+
} else {
|
|
152
|
+
onDispatchAction(action, true);
|
|
107
153
|
}
|
|
108
154
|
|
|
109
155
|
if (onRouteFocusParent !== undefined) {
|
|
@@ -120,19 +166,44 @@ export function useOnAction({
|
|
|
120
166
|
}
|
|
121
167
|
}
|
|
122
168
|
|
|
169
|
+
const isSourceInCurrentNavigator =
|
|
170
|
+
action.source !== undefined &&
|
|
171
|
+
state.routes.some((r) => r.key === action.source);
|
|
172
|
+
|
|
123
173
|
if (onActionParent !== undefined) {
|
|
124
174
|
// Bubble action to the parent if the current navigator didn't handle it
|
|
125
|
-
|
|
175
|
+
const parentAction =
|
|
176
|
+
isSourceInCurrentNavigator && key !== undefined
|
|
177
|
+
? {
|
|
178
|
+
...action,
|
|
179
|
+
// If the `source` belonged to the current navigator,
|
|
180
|
+
// rewrite the `source` to the parent screen's key when bubbling
|
|
181
|
+
// This will let parent handle it relative to the child that dispatched the action
|
|
182
|
+
source: key,
|
|
183
|
+
}
|
|
184
|
+
: action;
|
|
185
|
+
|
|
186
|
+
if (onActionParent(parentAction, visitedNavigators)) {
|
|
126
187
|
return true;
|
|
127
188
|
}
|
|
128
189
|
}
|
|
129
190
|
|
|
130
191
|
if (typeof action.target === 'string') {
|
|
131
192
|
// If the action wasn't handled by current navigator or a parent navigator, let children handle it
|
|
193
|
+
const childAction = isSourceInCurrentNavigator
|
|
194
|
+
? {
|
|
195
|
+
...action,
|
|
196
|
+
// If the `source` belonged to the current navigator,
|
|
197
|
+
// remove it when targeting a child navigator
|
|
198
|
+
// So child navigators can handle it based on the focused screen
|
|
199
|
+
source: undefined,
|
|
200
|
+
}
|
|
201
|
+
: action;
|
|
202
|
+
|
|
132
203
|
for (let i = actionListeners.length - 1; i >= 0; i--) {
|
|
133
204
|
const listener = actionListeners[i];
|
|
134
205
|
|
|
135
|
-
if (listener(
|
|
206
|
+
if (listener?.(childAction, visitedNavigators)) {
|
|
136
207
|
return true;
|
|
137
208
|
}
|
|
138
209
|
}
|
|
@@ -143,7 +214,9 @@ export function useOnAction({
|
|
|
143
214
|
[
|
|
144
215
|
actionListeners,
|
|
145
216
|
beforeRemoveListeners,
|
|
217
|
+
consumedParams,
|
|
146
218
|
emitter,
|
|
219
|
+
flushUpdates,
|
|
147
220
|
getState,
|
|
148
221
|
key,
|
|
149
222
|
onActionParent,
|
|
@@ -151,6 +224,7 @@ export function useOnAction({
|
|
|
151
224
|
onRouteFocusParent,
|
|
152
225
|
router,
|
|
153
226
|
setState,
|
|
227
|
+
tree,
|
|
154
228
|
]
|
|
155
229
|
);
|
|
156
230
|
|
|
@@ -160,7 +234,7 @@ export function useOnAction({
|
|
|
160
234
|
beforeRemoveListeners,
|
|
161
235
|
});
|
|
162
236
|
|
|
163
|
-
React.
|
|
237
|
+
React.useInsertionEffect(
|
|
164
238
|
() => addListenerParent?.('action', onAction),
|
|
165
239
|
[addListenerParent, onAction]
|
|
166
240
|
);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ParamListBase } from '@react-navigation/routers';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { useNavigationBuilderContext } from './NavigationBuilderContext';
|
|
5
|
+
import { NavigationRouteContext } from './NavigationProvider';
|
|
6
|
+
import type { NavigationHelpers } from './types';
|
|
7
|
+
|
|
8
|
+
type Options = {
|
|
9
|
+
navigation: NavigationHelpers<ParamListBase>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Hook which lets the container access the navigation object of the root navigator.
|
|
14
|
+
* It's used for the navigation object returned by `useNavigation` outside a screen.
|
|
15
|
+
*/
|
|
16
|
+
export function useOnGetNavigation({ navigation }: Options) {
|
|
17
|
+
const { addKeyedListener } = useNavigationBuilderContext();
|
|
18
|
+
|
|
19
|
+
const route = React.use(NavigationRouteContext);
|
|
20
|
+
|
|
21
|
+
React.useInsertionEffect(() => {
|
|
22
|
+
// We only register if this is the root navigator
|
|
23
|
+
// i.e. there is no parent route
|
|
24
|
+
if (route != null) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return addKeyedListener?.('getNavigation', 'root', () => navigation);
|
|
29
|
+
}, [addKeyedListener, navigation, route]);
|
|
30
|
+
}
|
package/src/useOnGetState.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { isArrayEqual } from './isArrayEqual';
|
|
5
5
|
import {
|
|
6
6
|
type GetStateListener,
|
|
7
|
-
|
|
7
|
+
useNavigationBuilderContext,
|
|
8
8
|
} from './NavigationBuilderContext';
|
|
9
9
|
import { NavigationRouteContext } from './NavigationProvider';
|
|
10
10
|
|
|
@@ -14,8 +14,10 @@ type Options = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export function useOnGetState({ getState, getStateListeners }: Options) {
|
|
17
|
-
const { addKeyedListener } =
|
|
18
|
-
|
|
17
|
+
const { addKeyedListener } = useNavigationBuilderContext();
|
|
18
|
+
|
|
19
|
+
const route = React.use(NavigationRouteContext);
|
|
20
|
+
|
|
19
21
|
const key = route ? route.key : 'root';
|
|
20
22
|
|
|
21
23
|
const getRehydratedState = React.useCallback(() => {
|
|
@@ -39,7 +41,9 @@ export function useOnGetState({ getState, getStateListeners }: Options) {
|
|
|
39
41
|
return { ...state, routes };
|
|
40
42
|
}, [getState, getStateListeners]);
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
// Use insertion effect to preserve the listener under `<Activity mode="hidden">`
|
|
45
|
+
// So `getRootState` will still return state of nested navigators
|
|
46
|
+
React.useInsertionEffect(() => {
|
|
43
47
|
return addKeyedListener?.('getState', key, getRehydratedState);
|
|
44
48
|
}, [addKeyedListener, getRehydratedState, key]);
|
|
45
49
|
}
|