@react-navigation/core 8.0.0-alpha.1 → 8.0.0-alpha.11

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.
Files changed (163) hide show
  1. package/lib/module/BaseNavigationContainer.js +14 -7
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/ConsumedParamsContext.js +5 -0
  4. package/lib/module/ConsumedParamsContext.js.map +1 -0
  5. package/lib/module/NavigationBuilderContext.js +1 -0
  6. package/lib/module/NavigationBuilderContext.js.map +1 -1
  7. package/lib/module/NavigationIndependentTree.js +8 -4
  8. package/lib/module/NavigationIndependentTree.js.map +1 -1
  9. package/lib/module/NavigationProvider.js +14 -3
  10. package/lib/module/NavigationProvider.js.map +1 -1
  11. package/lib/module/NavigationStateContext.js.map +1 -1
  12. package/lib/module/PreventRemoveProvider.js +3 -3
  13. package/lib/module/PreventRemoveProvider.js.map +1 -1
  14. package/lib/module/SceneView.js +46 -56
  15. package/lib/module/SceneView.js.map +1 -1
  16. package/lib/module/StaticNavigation.js +34 -4
  17. package/lib/module/StaticNavigation.js.map +1 -1
  18. package/lib/module/createNavigatorFactory.js +22 -1
  19. package/lib/module/createNavigatorFactory.js.map +1 -1
  20. package/lib/module/getPathFromState.js +25 -3
  21. package/lib/module/getPathFromState.js.map +1 -1
  22. package/lib/module/getStateFromPath.js +158 -73
  23. package/lib/module/getStateFromPath.js.map +1 -1
  24. package/lib/module/getStateFromRouteParams.js +24 -0
  25. package/lib/module/getStateFromRouteParams.js.map +1 -0
  26. package/lib/module/index.js +1 -1
  27. package/lib/module/index.js.map +1 -1
  28. package/lib/module/theming/useTheme.js +1 -1
  29. package/lib/module/theming/useTheme.js.map +1 -1
  30. package/lib/module/types.js.map +1 -1
  31. package/lib/module/useCurrentRender.js +1 -1
  32. package/lib/module/useCurrentRender.js.map +1 -1
  33. package/lib/module/useDescriptors.js +12 -43
  34. package/lib/module/useDescriptors.js.map +1 -1
  35. package/lib/module/useFocusEvents.js +1 -1
  36. package/lib/module/useFocusEvents.js.map +1 -1
  37. package/lib/module/useFocusedListenersChildrenAdapter.js +1 -1
  38. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  39. package/lib/module/useIsFocused.js +7 -12
  40. package/lib/module/useIsFocused.js.map +1 -1
  41. package/lib/module/useNavigationBuilder.js +84 -38
  42. package/lib/module/useNavigationBuilder.js.map +1 -1
  43. package/lib/module/useNavigationCache.js +14 -56
  44. package/lib/module/useNavigationCache.js.map +1 -1
  45. package/lib/module/useNavigationHelpers.js +1 -1
  46. package/lib/module/useNavigationHelpers.js.map +1 -1
  47. package/lib/module/useNavigationIndependentTree.js +1 -1
  48. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  49. package/lib/module/useNavigationState.js +4 -2
  50. package/lib/module/useNavigationState.js.map +1 -1
  51. package/lib/module/useOnAction.js +1 -1
  52. package/lib/module/useOnAction.js.map +1 -1
  53. package/lib/module/useOnGetState.js +2 -2
  54. package/lib/module/useOnGetState.js.map +1 -1
  55. package/lib/module/useOnPreventRemove.js +2 -2
  56. package/lib/module/useOnPreventRemove.js.map +1 -1
  57. package/lib/module/useOnRouteFocus.js +1 -1
  58. package/lib/module/useOnRouteFocus.js.map +1 -1
  59. package/lib/module/useOptionsGetters.js +2 -2
  60. package/lib/module/useOptionsGetters.js.map +1 -1
  61. package/lib/module/usePreventRemoveContext.js +1 -1
  62. package/lib/module/usePreventRemoveContext.js.map +1 -1
  63. package/lib/module/useRegisterNavigator.js +1 -1
  64. package/lib/module/useRegisterNavigator.js.map +1 -1
  65. package/lib/module/useScheduleUpdate.js +1 -1
  66. package/lib/module/useScheduleUpdate.js.map +1 -1
  67. package/lib/module/useStateForPath.js +1 -1
  68. package/lib/module/useStateForPath.js.map +1 -1
  69. package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
  70. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  71. package/lib/typescript/src/ConsumedParamsContext.d.ts +8 -0
  72. package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
  73. package/lib/typescript/src/NavigationBuilderContext.d.ts +11 -5
  74. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  75. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
  76. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
  77. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  78. package/lib/typescript/src/NavigationProvider.d.ts +4 -4
  79. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  80. package/lib/typescript/src/NavigationStateContext.d.ts +3 -3
  81. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  82. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  83. package/lib/typescript/src/StaticContainer.d.ts +1 -1
  84. package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
  85. package/lib/typescript/src/StaticNavigation.d.ts +39 -24
  86. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  87. package/lib/typescript/src/createNavigatorFactory.d.ts +1 -1
  88. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  89. package/lib/typescript/src/findFocusedRoute.d.ts +3 -3
  90. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  91. package/lib/typescript/src/getActionFromState.d.ts +3 -3
  92. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  93. package/lib/typescript/src/getPathFromState.d.ts +2 -2
  94. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  95. package/lib/typescript/src/getStateFromPath.d.ts +3 -3
  96. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  97. package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
  98. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
  99. package/lib/typescript/src/index.d.ts +2 -1
  100. package/lib/typescript/src/index.d.ts.map +1 -1
  101. package/lib/typescript/src/types.d.ts +144 -82
  102. package/lib/typescript/src/types.d.ts.map +1 -1
  103. package/lib/typescript/src/useDescriptors.d.ts +12 -25
  104. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  105. package/lib/typescript/src/useIsFocused.d.ts +3 -0
  106. package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
  107. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  108. package/lib/typescript/src/useNavigationBuilder.d.ts +20 -29
  109. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  110. package/lib/typescript/src/useNavigationCache.d.ts +2 -42
  111. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  112. package/lib/typescript/src/useNavigationHelpers.d.ts +18 -16
  113. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  114. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  115. package/lib/typescript/src/useOnAction.d.ts +6 -6
  116. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  117. package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
  118. package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
  119. package/lib/typescript/src/useRouteCache.d.ts +2 -2
  120. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  121. package/lib/typescript/src/utilities.d.ts +42 -3
  122. package/lib/typescript/src/utilities.d.ts.map +1 -1
  123. package/package.json +20 -18
  124. package/src/BaseNavigationContainer.tsx +332 -326
  125. package/src/ConsumedParamsContext.tsx +10 -0
  126. package/src/NavigationBuilderContext.tsx +14 -8
  127. package/src/NavigationFocusedRouteStateContext.tsx +4 -4
  128. package/src/NavigationIndependentTree.tsx +8 -5
  129. package/src/NavigationProvider.tsx +17 -3
  130. package/src/NavigationStateContext.tsx +5 -6
  131. package/src/PreventRemoveProvider.tsx +3 -3
  132. package/src/SceneView.tsx +58 -56
  133. package/src/StaticNavigation.tsx +121 -51
  134. package/src/createNavigatorFactory.tsx +35 -4
  135. package/src/findFocusedRoute.tsx +3 -3
  136. package/src/getActionFromState.tsx +7 -7
  137. package/src/getPathFromState.tsx +53 -9
  138. package/src/getStateFromPath.tsx +255 -97
  139. package/src/getStateFromRouteParams.tsx +60 -0
  140. package/src/index.tsx +1 -1
  141. package/src/theming/useTheme.tsx +1 -1
  142. package/src/types.tsx +330 -187
  143. package/src/useCurrentRender.tsx +1 -1
  144. package/src/useDescriptors.tsx +13 -48
  145. package/src/useFocusEvents.tsx +1 -1
  146. package/src/useFocusedListenersChildrenAdapter.tsx +1 -1
  147. package/src/useIsFocused.tsx +14 -21
  148. package/src/useNavigation.tsx +2 -2
  149. package/src/useNavigationBuilder.tsx +131 -49
  150. package/src/useNavigationCache.tsx +12 -73
  151. package/src/useNavigationHelpers.tsx +1 -1
  152. package/src/useNavigationIndependentTree.tsx +1 -1
  153. package/src/useNavigationState.tsx +6 -4
  154. package/src/useOnAction.tsx +8 -8
  155. package/src/useOnGetState.tsx +2 -2
  156. package/src/useOnPreventRemove.tsx +2 -2
  157. package/src/useOnRouteFocus.tsx +10 -12
  158. package/src/useOptionsGetters.tsx +2 -2
  159. package/src/usePreventRemoveContext.tsx +1 -1
  160. package/src/useRegisterNavigator.tsx +1 -1
  161. package/src/useScheduleUpdate.tsx +1 -3
  162. package/src/useStateForPath.tsx +1 -1
  163. package/src/utilities.tsx +94 -4
@@ -23,7 +23,7 @@ type Options = {
23
23
  * Mutating values like this is not safe in async mode, but it doesn't apply to SSR
24
24
  */
25
25
  export function useCurrentRender({ state, navigation, descriptors }: Options) {
26
- const current = React.useContext(CurrentRenderContext);
26
+ const current = React.use(CurrentRenderContext);
27
27
 
28
28
  if (current && navigation.isFocused()) {
29
29
  current.options = descriptors[state.routes[state.index].key].options;
@@ -67,7 +67,7 @@ type Options<
67
67
  ScreenOptions extends {},
68
68
  EventMap extends EventMapBase,
69
69
  > = {
70
- state: State;
70
+ routes: State['routes'];
71
71
  screens: Record<
72
72
  string,
73
73
  ScreenConfigWithParent<State, ScreenOptions, EventMap>
@@ -99,7 +99,7 @@ export function useDescriptors<
99
99
  ScreenOptions extends {},
100
100
  EventMap extends EventMapBase,
101
101
  >({
102
- state,
102
+ routes,
103
103
  screens,
104
104
  navigation,
105
105
  screenOptions,
@@ -113,17 +113,18 @@ export function useDescriptors<
113
113
  router,
114
114
  emitter,
115
115
  }: Options<State, ScreenOptions, EventMap>) {
116
- const theme = React.useContext(ThemeContext);
116
+ const theme = React.use(ThemeContext);
117
117
  const [options, setOptions] = React.useState<Record<string, ScreenOptions>>(
118
118
  {}
119
119
  );
120
120
  const {
121
121
  onDispatchAction,
122
+ onEmitEvent,
122
123
  onOptionsChange,
123
124
  scheduleUpdate,
124
125
  flushUpdates,
125
126
  stackRef,
126
- } = React.useContext(NavigationBuilderContext);
127
+ } = React.use(NavigationBuilderContext);
127
128
 
128
129
  const context = React.useMemo(
129
130
  () => ({
@@ -133,6 +134,7 @@ export function useDescriptors<
133
134
  addKeyedListener,
134
135
  onRouteFocus,
135
136
  onDispatchAction,
137
+ onEmitEvent,
136
138
  onOptionsChange,
137
139
  scheduleUpdate,
138
140
  flushUpdates,
@@ -145,6 +147,7 @@ export function useDescriptors<
145
147
  addKeyedListener,
146
148
  onRouteFocus,
147
149
  onDispatchAction,
150
+ onEmitEvent,
148
151
  onOptionsChange,
149
152
  scheduleUpdate,
150
153
  flushUpdates,
@@ -152,13 +155,13 @@ export function useDescriptors<
152
155
  ]
153
156
  );
154
157
 
155
- const { base, navigations } = useNavigationCache<
158
+ const navigations = useNavigationCache<
156
159
  State,
157
160
  ScreenOptions,
158
161
  EventMap,
159
162
  ActionHelpers
160
163
  >({
161
- state,
164
+ routes,
162
165
  getState,
163
166
  navigation,
164
167
  setOptions,
@@ -166,7 +169,7 @@ export function useDescriptors<
166
169
  emitter,
167
170
  });
168
171
 
169
- const routes = useRouteCache(state.routes);
172
+ const cachedRoutes = useRouteCache(routes);
170
173
 
171
174
  const getOptions = (
172
175
  route: RouteProp<ParamListBase, string>,
@@ -273,7 +276,7 @@ export function useDescriptors<
273
276
  );
274
277
  };
275
278
 
276
- const descriptors = routes.reduce<
279
+ const descriptors = cachedRoutes.reduce<
277
280
  Record<
278
281
  string,
279
282
  Descriptor<
@@ -292,12 +295,7 @@ export function useDescriptors<
292
295
  >((acc, route, i) => {
293
296
  const navigation = navigations[route.key];
294
297
  const customOptions = getOptions(route, navigation, options[route.key]);
295
- const element = render(
296
- route,
297
- navigation,
298
- customOptions,
299
- state.routes[i].state
300
- );
298
+ const element = render(route, navigation, customOptions, routes[i]?.state);
301
299
 
302
300
  acc[route.key] = {
303
301
  route,
@@ -311,38 +309,5 @@ export function useDescriptors<
311
309
  return acc;
312
310
  }, {});
313
311
 
314
- /**
315
- * Create a descriptor object for a route.
316
- *
317
- * @param route Route object for which the descriptor should be created
318
- * @param placeholder Whether the descriptor should be a placeholder, e.g. for a route not yet in the state
319
- * @returns Descriptor object
320
- */
321
- const describe = (route: RouteProp<ParamListBase>, placeholder: boolean) => {
322
- if (!placeholder) {
323
- if (!(route.key in descriptors)) {
324
- throw new Error(`Couldn't find a route with the key ${route.key}.`);
325
- }
326
-
327
- return descriptors[route.key];
328
- }
329
-
330
- const navigation = base;
331
- const customOptions = getOptions(route, navigation, {});
332
- const element = render(route, navigation, customOptions, undefined);
333
-
334
- return {
335
- route,
336
- navigation,
337
- render() {
338
- return element;
339
- },
340
- options: customOptions as ScreenOptions,
341
- };
342
- };
343
-
344
- return {
345
- describe,
346
- descriptors,
347
- };
312
+ return descriptors;
348
313
  }
@@ -17,7 +17,7 @@ export function useFocusEvents<State extends NavigationState>({
17
17
  state,
18
18
  emitter,
19
19
  }: Options<State>) {
20
- const navigation = React.useContext(NavigationContext);
20
+ const navigation = React.use(NavigationContext);
21
21
  const lastFocusedKeyRef = React.useRef<string | undefined>(undefined);
22
22
 
23
23
  const currentFocusedKey = state.routes[state.index].key;
@@ -20,7 +20,7 @@ export function useFocusedListenersChildrenAdapter({
20
20
  navigation,
21
21
  focusedListeners,
22
22
  }: Options) {
23
- const { addListener } = React.useContext(NavigationBuilderContext);
23
+ const { addListener } = React.use(NavigationBuilderContext);
24
24
 
25
25
  const listener = React.useCallback(
26
26
  (callback: FocusedNavigationCallback<any>) => {
@@ -1,32 +1,25 @@
1
1
  import * as React from 'react';
2
2
 
3
- import { useNavigation } from './useNavigation';
3
+ export const FocusedRouteKeyContext = React.createContext<string | undefined>(
4
+ undefined
5
+ );
6
+
7
+ export const IsFocusedContext = React.createContext<boolean | undefined>(
8
+ undefined
9
+ );
4
10
 
5
11
  /**
6
12
  * Hook to get the current focus state of the screen. Returns a `true` if screen is focused, otherwise `false`.
7
13
  * This can be used if a component needs to render something based on the focus state.
8
14
  */
9
15
  export function useIsFocused(): boolean {
10
- const navigation = useNavigation();
11
-
12
- const subscribe = React.useCallback(
13
- (callback: () => void) => {
14
- const unsubscribeFocus = navigation.addListener('focus', callback);
15
- const unsubscribeBlur = navigation.addListener('blur', callback);
16
-
17
- return () => {
18
- unsubscribeFocus();
19
- unsubscribeBlur();
20
- };
21
- },
22
- [navigation]
23
- );
16
+ const isFocused = React.use(IsFocusedContext);
24
17
 
25
- const value = React.useSyncExternalStore(
26
- subscribe,
27
- navigation.isFocused,
28
- navigation.isFocused
29
- );
18
+ if (isFocused === undefined) {
19
+ throw new Error(
20
+ "Couldn't determine focus state. Is your component inside a screen in a navigator?"
21
+ );
22
+ }
30
23
 
31
- return value;
24
+ return isFocused;
32
25
  }
@@ -27,8 +27,8 @@ export function useNavigation<
27
27
  >(): NavigationListForNavigator<Navigator>[keyof NavigationListForNavigator<Navigator>];
28
28
  export function useNavigation<
29
29
  const Navigator = RootNavigator,
30
- const RouteName extends
31
- keyof NavigationListForNested<Navigator> = keyof NavigationListForNested<Navigator>,
30
+ const RouteName extends keyof NavigationListForNested<Navigator> =
31
+ keyof NavigationListForNested<Navigator>,
32
32
  >(name: RouteName): NavigationListForNested<Navigator>[RouteName];
33
33
  export function useNavigation(name?: string): unknown {
34
34
  const root = React.use(NavigationContainerRefContext);
@@ -15,10 +15,12 @@ import * as React from 'react';
15
15
  import { isValidElementType } from 'react-is';
16
16
  import useLatestCallback from 'use-latest-callback';
17
17
 
18
+ import { ConsumedParamsContext } from './ConsumedParamsContext';
18
19
  import { deepFreeze } from './deepFreeze';
19
20
  import { Group } from './Group';
20
21
  import { isArrayEqual } from './isArrayEqual';
21
22
  import { isRecordEqual } from './isRecordEqual';
23
+ import { NavigationBuilderContext } from './NavigationBuilderContext';
22
24
  import { NavigationHelpersContext } from './NavigationHelpersContext';
23
25
  import { NavigationMetaContext } from './NavigationMetaContext';
24
26
  import { NavigationRouteContext } from './NavigationProvider';
@@ -41,6 +43,7 @@ import { type ScreenConfigWithParent, useDescriptors } from './useDescriptors';
41
43
  import { useEventEmitter } from './useEventEmitter';
42
44
  import { useFocusedListenersChildrenAdapter } from './useFocusedListenersChildrenAdapter';
43
45
  import { useFocusEvents } from './useFocusEvents';
46
+ import { FocusedRouteKeyContext } from './useIsFocused';
44
47
  import { useKeyedChildListeners } from './useKeyedChildListeners';
45
48
  import { useLazyValue } from './useLazyValue';
46
49
  import { useNavigationHelpers } from './useNavigationHelpers';
@@ -57,7 +60,7 @@ PrivateValueStore;
57
60
 
58
61
  type NavigatorRoute = {
59
62
  key: string;
60
- params?: NavigatorScreenParams<ParamListBase>;
63
+ params?: NavigatorScreenParams<ParamListBase> | undefined;
61
64
  };
62
65
 
63
66
  const isScreen = (
@@ -319,9 +322,14 @@ export function useNavigationBuilder<
319
322
  ) {
320
323
  const navigatorKey = useRegisterNavigator();
321
324
 
322
- const route = React.useContext(NavigationRouteContext) as
323
- | NavigatorRoute
324
- | undefined;
325
+ const route = React.use(NavigationRouteContext) as NavigatorRoute | undefined;
326
+
327
+ const consumedParams = React.use(ConsumedParamsContext);
328
+
329
+ const isNestedParamsConsumed =
330
+ typeof route?.params === 'object' && route.params != null
331
+ ? consumedParams?.isConsumed(route.params)
332
+ : false;
325
333
 
326
334
  const {
327
335
  children,
@@ -417,7 +425,9 @@ export function useNavigationBuilder<
417
425
  );
418
426
 
419
427
  const isStateInitialized = React.useCallback(
420
- (state: NavigationState | PartialState<NavigationState> | undefined) =>
428
+ <T extends NavigationState>(
429
+ state: T | PartialState<T> | undefined
430
+ ): state is T =>
421
431
  state !== undefined && state.stale === false && isStateValid(state),
422
432
  [isStateValid]
423
433
  );
@@ -435,16 +445,22 @@ export function useNavigationBuilder<
435
445
  setKey,
436
446
  getKey,
437
447
  getIsInitial,
438
- } = React.useContext(NavigationStateContext);
448
+ } = React.use(NavigationStateContext);
439
449
 
440
- const stateCleanedUp = React.useRef(false);
450
+ const stateCleanupRef = React.useRef<boolean>(false);
451
+ const lastStateRef = React.useRef<State | PartialState<State> | undefined>(
452
+ undefined
453
+ );
441
454
 
442
455
  const setState = useLatestCallback(
443
- (state: NavigationState | PartialState<NavigationState> | undefined) => {
444
- if (stateCleanedUp.current) {
456
+ (state: State | PartialState<State> | undefined) => {
457
+ if (stateCleanupRef.current) {
458
+ // Store the state locally in case the current navigator is in `Activity`
459
+ lastStateRef.current = state;
460
+
445
461
  // State might have been already cleaned up due to unmount
446
- // We do not want to expose API allowing to override this
447
- // This would lead to old data preservation on main navigator unmount
462
+ // We don't want to update `route.state` in parent
463
+ // Otherwise it will be reused if a new navigator gets mounted
448
464
  return;
449
465
  }
450
466
 
@@ -456,11 +472,32 @@ export function useNavigationBuilder<
456
472
  stateBeforeInitialization,
457
473
  initializedState,
458
474
  isFirstStateInitialization,
475
+ paramsUsedForInitialization,
459
476
  ] = React.useMemo((): [
460
477
  PartialState<State> | undefined,
461
478
  State | undefined,
462
479
  boolean,
480
+ object | undefined,
463
481
  ] => {
482
+ // If the state was already cleaned up, but we have it stored in ref,
483
+ // It likely got cleaned up due to `<Activity mode="hidden">`
484
+ // We should reuse this state to avoid remounting screens
485
+ if (
486
+ stateCleanupRef.current &&
487
+ lastStateRef.current &&
488
+ isStateValid(lastStateRef.current)
489
+ ) {
490
+ const state: State = isStateInitialized(lastStateRef.current)
491
+ ? lastStateRef.current
492
+ : router.getRehydratedState(lastStateRef.current, {
493
+ routeNames,
494
+ routeParamList,
495
+ routeGetIdList,
496
+ });
497
+
498
+ return [undefined, state, false, undefined];
499
+ }
500
+
464
501
  const initialRouteParamList = routeNames.reduce<
465
502
  Record<string, object | undefined>
466
503
  >((acc, curr) => {
@@ -493,7 +530,8 @@ export function useNavigationBuilder<
493
530
  !(
494
531
  typeof route?.params?.screen === 'string' &&
495
532
  route?.params?.initial !== false
496
- )
533
+ ) &&
534
+ !isNestedParamsConsumed
497
535
  ) {
498
536
  return [
499
537
  undefined,
@@ -503,28 +541,40 @@ export function useNavigationBuilder<
503
541
  routeGetIdList,
504
542
  }),
505
543
  true,
544
+ undefined,
506
545
  ];
507
546
  } else {
508
- const stateFromParams = getStateFromParams(route?.params);
509
- const stateBeforeInitialization = (stateFromParams ??
510
- currentState) as PartialState<State>;
511
- const hydratedState = router.getRehydratedState(
512
- stateBeforeInitialization,
513
- {
514
- routeNames,
515
- routeParamList: initialRouteParamList,
516
- routeGetIdList,
517
- }
518
- );
547
+ const paramsForState = isNestedParamsConsumed ? undefined : route?.params;
548
+ const stateFromParams = paramsForState
549
+ ? getStateFromParams(paramsForState)
550
+ : undefined;
551
+
552
+ const stateBeforeInitialization = (stateFromParams ?? currentState) as
553
+ | PartialState<State>
554
+ | undefined;
555
+
556
+ const hydratedState =
557
+ stateBeforeInitialization == null
558
+ ? router.getInitialState({
559
+ routeNames,
560
+ routeParamList: initialRouteParamList,
561
+ routeGetIdList,
562
+ })
563
+ : router.getRehydratedState(stateBeforeInitialization, {
564
+ routeNames,
565
+ routeParamList: initialRouteParamList,
566
+ routeGetIdList,
567
+ });
519
568
 
520
569
  if (
570
+ stateBeforeInitialization != null &&
521
571
  options.routeNamesChangeBehavior === 'lastUnhandled' &&
522
572
  doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)
523
573
  ) {
524
- return [stateBeforeInitialization, hydratedState, true];
574
+ return [stateBeforeInitialization, hydratedState, true, paramsForState];
525
575
  }
526
576
 
527
- return [undefined, hydratedState, false];
577
+ return [undefined, hydratedState, false, paramsForState];
528
578
  }
529
579
  // We explicitly don't include routeNames, route.params etc. in the dep list
530
580
  // below. We want to avoid forcing a new state to be calculated in those cases
@@ -602,22 +652,18 @@ export function useNavigationBuilder<
602
652
  });
603
653
  }
604
654
 
605
- const previousNestedParamsRef = React.useRef(route?.params);
606
-
607
- React.useEffect(() => {
608
- previousNestedParamsRef.current = route?.params;
609
- }, [route?.params]);
610
-
611
- if (route?.params) {
612
- const previousParams = previousNestedParamsRef.current;
655
+ let didConsumeNestedParams = route?.params === paramsUsedForInitialization;
613
656
 
657
+ if (route?.params && !didConsumeNestedParams) {
614
658
  let action: CommonActions.Action | undefined;
615
659
 
616
660
  if (
617
661
  typeof route.params.state === 'object' &&
618
662
  route.params.state != null &&
619
- route.params !== previousParams
663
+ !isNestedParamsConsumed
620
664
  ) {
665
+ didConsumeNestedParams = true;
666
+
621
667
  if (
622
668
  options.routeNamesChangeBehavior === 'lastUnhandled' &&
623
669
  doesStateHaveOnlyInvalidRoutes(route.params.state)
@@ -632,8 +678,10 @@ export function useNavigationBuilder<
632
678
  } else if (
633
679
  typeof route.params.screen === 'string' &&
634
680
  ((route.params.initial === false && isFirstStateInitialization) ||
635
- route.params !== previousParams)
681
+ !isNestedParamsConsumed)
636
682
  ) {
683
+ didConsumeNestedParams = true;
684
+
637
685
  if (
638
686
  options.routeNamesChangeBehavior === 'lastUnhandled' &&
639
687
  !routeNames.includes(route.params.screen)
@@ -674,14 +722,24 @@ export function useNavigationBuilder<
674
722
  : nextState;
675
723
  }
676
724
 
677
- const shouldUpdate =
678
- state !== nextState ||
679
- typeof route?.params?.state === 'object' ||
680
- typeof route?.params?.screen === 'string';
725
+ const setConsumedParams = consumedParams?.setConsumed;
726
+
727
+ React.useEffect(() => {
728
+ if (
729
+ setConsumedParams &&
730
+ didConsumeNestedParams &&
731
+ typeof route?.params === 'object' &&
732
+ route.params != null
733
+ ) {
734
+ setConsumedParams(route.params);
735
+ }
736
+ }, [didConsumeNestedParams, route?.params, setConsumedParams]);
737
+
738
+ const shouldUpdate = state !== nextState;
681
739
 
682
740
  useScheduleUpdate(() => {
683
741
  if (shouldUpdate) {
684
- // If the state needs to be updated, we'll schedule an update
742
+ // Schedule an update if the state needs to be updated
685
743
  setState(nextState);
686
744
 
687
745
  if (shouldClearUnhandledState) {
@@ -695,25 +753,35 @@ export function useNavigationBuilder<
695
753
  // So we override the state object we return to use the latest state as soon as possible
696
754
  state = nextState;
697
755
 
756
+ // Last state to reuse if component gets cleaned up due to `<Activity mode="hidden">`
757
+ React.useEffect(() => {
758
+ lastStateRef.current = state;
759
+ });
760
+
761
+ const lastNotifiedStateRef = React.useRef<State | null>(null);
762
+
698
763
  React.useEffect(() => {
699
764
  // In strict mode, React will double-invoke effects.
700
765
  // So we need to reset the flag if component was not unmounted
701
- stateCleanedUp.current = false;
766
+ stateCleanupRef.current = false;
702
767
 
703
768
  setKey(navigatorKey);
704
769
 
705
- if (!getIsInitial()) {
770
+ if (!getIsInitial() && lastNotifiedStateRef.current !== state) {
706
771
  // If it's not initial render, we need to update the state
707
772
  // This will make sure that our container gets notifier of state changes due to new mounts
708
773
  // This is necessary for proper screen tracking, URL updates etc.
709
- setState(nextState);
774
+ // We only notify if the state is different what we already notified
775
+ // Otherwise this goes into a loop when inside `<Activity mode="hidden">`
776
+ setState(state);
777
+ lastNotifiedStateRef.current = state;
710
778
  }
711
779
 
712
780
  return () => {
713
781
  // We need to clean up state for this navigator on unmount
714
782
  if (getCurrentState() !== undefined && getKey() === navigatorKey) {
715
783
  setCurrentState(undefined);
716
- stateCleanedUp.current = true;
784
+ stateCleanupRef.current = true;
717
785
  }
718
786
  };
719
787
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -742,6 +810,8 @@ export function useNavigationBuilder<
742
810
  );
743
811
  });
744
812
 
813
+ const { onEmitEvent } = React.use(NavigationBuilderContext);
814
+
745
815
  const emitter = useEventEmitter<EventMapCore<State>>((e) => {
746
816
  const routeNames = [];
747
817
 
@@ -793,6 +863,13 @@ export function useNavigationBuilder<
793
863
  .filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
794
864
 
795
865
  listeners.forEach((listener) => listener?.(e));
866
+
867
+ onEmitEvent({
868
+ type: e.type,
869
+ data: e.data,
870
+ target: e.target,
871
+ defaultPrevented: e.defaultPrevented,
872
+ });
796
873
  });
797
874
 
798
875
  useFocusEvents({ state, emitter });
@@ -827,7 +904,7 @@ export function useNavigationBuilder<
827
904
  setState,
828
905
  });
829
906
 
830
- const onUnhandledActionParent = React.useContext(UnhandledActionContext);
907
+ const onUnhandledActionParent = React.use(UnhandledActionContext);
831
908
 
832
909
  const onUnhandledAction = useLatestCallback((action: NavigationAction) => {
833
910
  if (
@@ -887,13 +964,15 @@ export function useNavigationBuilder<
887
964
  getStateListeners: keyedListeners.getState,
888
965
  });
889
966
 
890
- const { describe, descriptors } = useDescriptors<
967
+ const descriptors = useDescriptors<
891
968
  State,
892
969
  ActionHelpers,
893
970
  ScreenOptions,
894
971
  EventMap
895
972
  >({
896
- state,
973
+ routes: router.getRoutesFromState
974
+ ? router.getRoutesFromState(state)
975
+ : state.routes,
897
976
  screens,
898
977
  navigation,
899
978
  screenOptions,
@@ -930,7 +1009,11 @@ export function useNavigationBuilder<
930
1009
  <NavigationMetaContext.Provider value={undefined}>
931
1010
  <NavigationHelpersContext.Provider value={navigation}>
932
1011
  <NavigationStateListenerProvider state={state}>
933
- <PreventRemoveProvider>{element}</PreventRemoveProvider>
1012
+ <FocusedRouteKeyContext.Provider
1013
+ value={state.routes[state.index].key}
1014
+ >
1015
+ <PreventRemoveProvider>{element}</PreventRemoveProvider>
1016
+ </FocusedRouteKeyContext.Provider>
934
1017
  </NavigationStateListenerProvider>
935
1018
  </NavigationHelpersContext.Provider>
936
1019
  </NavigationMetaContext.Provider>
@@ -940,7 +1023,6 @@ export function useNavigationBuilder<
940
1023
  return {
941
1024
  state,
942
1025
  navigation,
943
- describe,
944
1026
  descriptors,
945
1027
  NavigationContent,
946
1028
  };