@react-navigation/core 8.0.0-alpha.3 → 8.0.0-alpha.30

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 (283) hide show
  1. package/lib/module/BaseNavigationContainer.js +34 -17
  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/DataLoading.js +127 -0
  6. package/lib/module/DataLoading.js.map +1 -0
  7. package/lib/module/NavigationBuilderContext.js +1 -0
  8. package/lib/module/NavigationBuilderContext.js.map +1 -1
  9. package/lib/module/NavigationIndependentTree.js +17 -8
  10. package/lib/module/NavigationIndependentTree.js.map +1 -1
  11. package/lib/module/NavigationProvider.js +22 -11
  12. package/lib/module/NavigationProvider.js.map +1 -1
  13. package/lib/module/NavigationStateContext.js.map +1 -1
  14. package/lib/module/PreventRemoveContext.js.map +1 -1
  15. package/lib/module/PreventRemoveProvider.js +37 -27
  16. package/lib/module/PreventRemoveProvider.js.map +1 -1
  17. package/lib/module/SceneView.js +7 -40
  18. package/lib/module/SceneView.js.map +1 -1
  19. package/lib/module/StaticNavigation.js +179 -50
  20. package/lib/module/StaticNavigation.js.map +1 -1
  21. package/lib/module/StaticTreeContext.js +5 -0
  22. package/lib/module/StaticTreeContext.js.map +1 -0
  23. package/lib/module/checkSerializable.js +18 -13
  24. package/lib/module/checkSerializable.js.map +1 -1
  25. package/lib/module/createNavigationContainerRef.js +6 -8
  26. package/lib/module/createNavigationContainerRef.js.map +1 -1
  27. package/lib/module/createNavigatorFactory.js +27 -5
  28. package/lib/module/createNavigatorFactory.js.map +1 -1
  29. package/lib/module/findFocusedRoute.js +7 -4
  30. package/lib/module/findFocusedRoute.js.map +1 -1
  31. package/lib/module/getActionFromState.js +45 -20
  32. package/lib/module/getActionFromState.js.map +1 -1
  33. package/lib/module/getPathFromState.js +171 -90
  34. package/lib/module/getPathFromState.js.map +1 -1
  35. package/lib/module/getPatternParts.js +20 -4
  36. package/lib/module/getPatternParts.js.map +1 -1
  37. package/lib/module/getStateFromPath.js +485 -214
  38. package/lib/module/getStateFromPath.js.map +1 -1
  39. package/lib/module/getStateFromRouteParams.js +24 -0
  40. package/lib/module/getStateFromRouteParams.js.map +1 -0
  41. package/lib/module/index.js +5 -4
  42. package/lib/module/index.js.map +1 -1
  43. package/lib/module/theming/useTheme.js +1 -1
  44. package/lib/module/theming/useTheme.js.map +1 -1
  45. package/lib/module/types.js +35 -0
  46. package/lib/module/types.js.map +1 -1
  47. package/lib/module/useDescriptors.js +19 -11
  48. package/lib/module/useDescriptors.js.map +1 -1
  49. package/lib/module/useEventEmitter.js +48 -33
  50. package/lib/module/useEventEmitter.js.map +1 -1
  51. package/lib/module/useFocusEvents.js +12 -4
  52. package/lib/module/useFocusEvents.js.map +1 -1
  53. package/lib/module/useFocusedListenersChildrenAdapter.js +2 -2
  54. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  55. package/lib/module/useIsFocused.js +7 -12
  56. package/lib/module/useIsFocused.js.map +1 -1
  57. package/lib/module/useKeyedChildListeners.js +4 -2
  58. package/lib/module/useKeyedChildListeners.js.map +1 -1
  59. package/lib/module/useLazyValue.js.map +1 -1
  60. package/lib/module/useNavigation.js +2 -15
  61. package/lib/module/useNavigation.js.map +1 -1
  62. package/lib/module/useNavigationBuilder.js +201 -131
  63. package/lib/module/useNavigationBuilder.js.map +1 -1
  64. package/lib/module/useNavigationCache.js +22 -17
  65. package/lib/module/useNavigationCache.js.map +1 -1
  66. package/lib/module/useNavigationHelpers.js +28 -10
  67. package/lib/module/useNavigationHelpers.js.map +1 -1
  68. package/lib/module/useNavigationIndependentTree.js +1 -1
  69. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  70. package/lib/module/useNavigationState.js +70 -35
  71. package/lib/module/useNavigationState.js.map +1 -1
  72. package/lib/module/useOnAction.js +37 -7
  73. package/lib/module/useOnAction.js.map +1 -1
  74. package/lib/module/useOnGetState.js +6 -3
  75. package/lib/module/useOnGetState.js.map +1 -1
  76. package/lib/module/useOnPreventRemove.js +39 -30
  77. package/lib/module/useOnPreventRemove.js.map +1 -1
  78. package/lib/module/useOnRouteFocus.js +1 -1
  79. package/lib/module/useOnRouteFocus.js.map +1 -1
  80. package/lib/module/useOptionsGetters.js +10 -5
  81. package/lib/module/useOptionsGetters.js.map +1 -1
  82. package/lib/module/usePreventRemove.js +10 -3
  83. package/lib/module/usePreventRemove.js.map +1 -1
  84. package/lib/module/usePreventRemoveContext.js +1 -1
  85. package/lib/module/usePreventRemoveContext.js.map +1 -1
  86. package/lib/module/useRegisterNavigator.js +2 -2
  87. package/lib/module/useRegisterNavigator.js.map +1 -1
  88. package/lib/module/useRoute.js +2 -0
  89. package/lib/module/useRoute.js.map +1 -1
  90. package/lib/module/useRouteCache.js +17 -11
  91. package/lib/module/useRouteCache.js.map +1 -1
  92. package/lib/module/useScheduleUpdate.js +9 -9
  93. package/lib/module/useScheduleUpdate.js.map +1 -1
  94. package/lib/module/useStateForPath.js +1 -1
  95. package/lib/module/useStateForPath.js.map +1 -1
  96. package/lib/module/useSyncState.js +7 -3
  97. package/lib/module/useSyncState.js.map +1 -1
  98. package/lib/module/validatePathConfig.js +50 -36
  99. package/lib/module/validatePathConfig.js.map +1 -1
  100. package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
  101. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  102. package/lib/typescript/src/ConsumedParamsContext.d.ts +3 -0
  103. package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
  104. package/lib/typescript/src/DataLoading.d.ts +21 -0
  105. package/lib/typescript/src/DataLoading.d.ts.map +1 -0
  106. package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
  107. package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
  108. package/lib/typescript/src/Group.d.ts +1 -1
  109. package/lib/typescript/src/Group.d.ts.map +1 -1
  110. package/lib/typescript/src/NavigationBuilderContext.d.ts +9 -8
  111. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  112. package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
  113. package/lib/typescript/src/NavigationContainerRefContext.d.ts.map +1 -1
  114. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
  115. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
  116. package/lib/typescript/src/NavigationHelpersContext.d.ts +1 -1
  117. package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
  118. package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
  119. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  120. package/lib/typescript/src/NavigationProvider.d.ts +12 -13
  121. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  122. package/lib/typescript/src/NavigationStateContext.d.ts +3 -3
  123. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  124. package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
  125. package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
  126. package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
  127. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  128. package/lib/typescript/src/SceneView.d.ts +3 -2
  129. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  130. package/lib/typescript/src/Screen.d.ts +1 -1
  131. package/lib/typescript/src/Screen.d.ts.map +1 -1
  132. package/lib/typescript/src/StaticContainer.d.ts +1 -1
  133. package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
  134. package/lib/typescript/src/StaticNavigation.d.ts +189 -109
  135. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  136. package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
  137. package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
  138. package/lib/typescript/src/checkSerializable.d.ts +8 -4
  139. package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
  140. package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
  141. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  142. package/lib/typescript/src/createNavigatorFactory.d.ts +23 -5
  143. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  144. package/lib/typescript/src/findFocusedRoute.d.ts +3 -3
  145. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  146. package/lib/typescript/src/getActionFromState.d.ts +4 -4
  147. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  148. package/lib/typescript/src/getPathFromState.d.ts +3 -3
  149. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  150. package/lib/typescript/src/getPatternParts.d.ts +1 -0
  151. package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
  152. package/lib/typescript/src/getStateFromPath.d.ts +5 -5
  153. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  154. package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
  155. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
  156. package/lib/typescript/src/index.d.ts +36 -33
  157. package/lib/typescript/src/index.d.ts.map +1 -1
  158. package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
  159. package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
  160. package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
  161. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  162. package/lib/typescript/src/theming/useTheme.d.ts +1 -1
  163. package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
  164. package/lib/typescript/src/types.d.ts +260 -159
  165. package/lib/typescript/src/types.d.ts.map +1 -1
  166. package/lib/typescript/src/useChildListeners.d.ts +3 -3
  167. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  168. package/lib/typescript/src/useComponent.d.ts +1 -1
  169. package/lib/typescript/src/useComponent.d.ts.map +1 -1
  170. package/lib/typescript/src/useDescriptors.d.ts +8 -8
  171. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  172. package/lib/typescript/src/useEventEmitter.d.ts +2 -2
  173. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  174. package/lib/typescript/src/useFocusEvents.d.ts +2 -2
  175. package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
  176. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
  177. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts.map +1 -1
  178. package/lib/typescript/src/useIsFocused.d.ts +3 -0
  179. package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
  180. package/lib/typescript/src/useKeyedChildListeners.d.ts +3 -3
  181. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  182. package/lib/typescript/src/useLazyValue.d.ts.map +1 -1
  183. package/lib/typescript/src/useNavigation.d.ts +4 -2
  184. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  185. package/lib/typescript/src/useNavigationBuilder.d.ts +23 -30
  186. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  187. package/lib/typescript/src/useNavigationCache.d.ts +3 -3
  188. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  189. package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
  190. package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
  191. package/lib/typescript/src/useNavigationHelpers.d.ts +19 -27
  192. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  193. package/lib/typescript/src/useNavigationState.d.ts +13 -3
  194. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  195. package/lib/typescript/src/useOnAction.d.ts +9 -9
  196. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  197. package/lib/typescript/src/useOnGetState.d.ts +1 -1
  198. package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
  199. package/lib/typescript/src/useOnPreventRemove.d.ts +5 -9
  200. package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
  201. package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
  202. package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
  203. package/lib/typescript/src/useOptionsGetters.d.ts +1 -1
  204. package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
  205. package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
  206. package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
  207. package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
  208. package/lib/typescript/src/useRoute.d.ts +7 -3
  209. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  210. package/lib/typescript/src/useRouteCache.d.ts +5 -5
  211. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  212. package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
  213. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  214. package/lib/typescript/src/useStateForPath.d.ts +1 -1
  215. package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
  216. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  217. package/lib/typescript/src/utilities.d.ts +74 -37
  218. package/lib/typescript/src/utilities.d.ts.map +1 -1
  219. package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
  220. package/package.json +23 -22
  221. package/src/BaseNavigationContainer.tsx +351 -333
  222. package/src/ConsumedParamsContext.tsx +5 -0
  223. package/src/DataLoading.tsx +203 -0
  224. package/src/NavigationBuilderContext.tsx +14 -9
  225. package/src/NavigationFocusedRouteStateContext.tsx +4 -4
  226. package/src/NavigationIndependentTree.tsx +18 -12
  227. package/src/NavigationProvider.tsx +26 -15
  228. package/src/NavigationStateContext.tsx +5 -6
  229. package/src/PreventRemoveContext.tsx +1 -0
  230. package/src/PreventRemoveProvider.tsx +51 -46
  231. package/src/SceneView.tsx +7 -39
  232. package/src/StaticNavigation.tsx +659 -307
  233. package/src/StaticTreeContext.tsx +7 -0
  234. package/src/checkSerializable.tsx +35 -19
  235. package/src/createNavigationContainerRef.tsx +12 -9
  236. package/src/createNavigatorFactory.tsx +92 -8
  237. package/src/findFocusedRoute.tsx +13 -8
  238. package/src/getActionFromState.tsx +86 -51
  239. package/src/getPathFromState.tsx +254 -128
  240. package/src/getPatternParts.tsx +25 -4
  241. package/src/getStateFromPath.tsx +811 -309
  242. package/src/getStateFromRouteParams.tsx +60 -0
  243. package/src/index.tsx +55 -5
  244. package/src/theming/useTheme.tsx +1 -1
  245. package/src/types.tsx +798 -373
  246. package/src/useDescriptors.tsx +28 -14
  247. package/src/useEventEmitter.tsx +52 -38
  248. package/src/useFocusEvents.tsx +15 -7
  249. package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
  250. package/src/useIsFocused.tsx +14 -21
  251. package/src/useKeyedChildListeners.tsx +4 -2
  252. package/src/useLazyValue.tsx +2 -2
  253. package/src/useNavigation.tsx +7 -24
  254. package/src/useNavigationBuilder.tsx +311 -186
  255. package/src/useNavigationCache.tsx +32 -25
  256. package/src/useNavigationHelpers.tsx +27 -10
  257. package/src/useNavigationIndependentTree.tsx +1 -1
  258. package/src/useNavigationState.tsx +93 -59
  259. package/src/useOnAction.tsx +61 -13
  260. package/src/useOnGetState.tsx +5 -3
  261. package/src/useOnPreventRemove.tsx +75 -42
  262. package/src/useOnRouteFocus.tsx +10 -12
  263. package/src/useOptionsGetters.tsx +11 -5
  264. package/src/usePreventRemove.tsx +12 -3
  265. package/src/usePreventRemoveContext.tsx +1 -1
  266. package/src/useRegisterNavigator.tsx +2 -2
  267. package/src/useRoute.tsx +20 -6
  268. package/src/useRouteCache.tsx +22 -16
  269. package/src/useScheduleUpdate.tsx +9 -10
  270. package/src/useStateForPath.tsx +1 -1
  271. package/src/useSyncState.tsx +8 -3
  272. package/src/utilities.tsx +144 -31
  273. package/src/validatePathConfig.tsx +86 -57
  274. package/lib/module/CurrentRenderContext.js +0 -10
  275. package/lib/module/CurrentRenderContext.js.map +0 -1
  276. package/lib/module/useCurrentRender.js +0 -19
  277. package/lib/module/useCurrentRender.js.map +0 -1
  278. package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
  279. package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
  280. package/lib/typescript/src/useCurrentRender.d.ts +0 -14
  281. package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
  282. package/src/CurrentRenderContext.tsx +0 -9
  283. package/src/useCurrentRender.tsx +0 -31
@@ -15,10 +15,10 @@ 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
- import { isRecordEqual } from './isRecordEqual';
22
22
  import { NavigationBuilderContext } from './NavigationBuilderContext';
23
23
  import { NavigationHelpersContext } from './NavigationHelpersContext';
24
24
  import { NavigationMetaContext } from './NavigationMetaContext';
@@ -37,11 +37,11 @@ import {
37
37
  import { UnhandledActionContext } from './UnhandledActionContext';
38
38
  import { useChildListeners } from './useChildListeners';
39
39
  import { useComponent } from './useComponent';
40
- import { useCurrentRender } from './useCurrentRender';
41
40
  import { type ScreenConfigWithParent, useDescriptors } from './useDescriptors';
42
41
  import { useEventEmitter } from './useEventEmitter';
43
42
  import { useFocusedListenersChildrenAdapter } from './useFocusedListenersChildrenAdapter';
44
43
  import { useFocusEvents } from './useFocusEvents';
44
+ import { FocusedRouteKeyContext } from './useIsFocused';
45
45
  import { useKeyedChildListeners } from './useKeyedChildListeners';
46
46
  import { useLazyValue } from './useLazyValue';
47
47
  import { useNavigationHelpers } from './useNavigationHelpers';
@@ -58,9 +58,17 @@ PrivateValueStore;
58
58
 
59
59
  type NavigatorRoute = {
60
60
  key: string;
61
- params?: NavigatorScreenParams<ParamListBase>;
61
+ params?: NavigatorScreenParams<ParamListBase> | undefined;
62
62
  };
63
63
 
64
+ const isNavigationState = (
65
+ state: unknown
66
+ ): state is NavigationState | PartialState<NavigationState> =>
67
+ state != null &&
68
+ typeof state === 'object' &&
69
+ 'routes' in state &&
70
+ Array.isArray(state.routes);
71
+
64
72
  const isScreen = (
65
73
  child: React.ReactElement<unknown>
66
74
  ): child is React.ReactElement<{
@@ -95,7 +103,7 @@ const getRouteConfigsFromChildren = <
95
103
  EventMap extends EventMapBase,
96
104
  >(
97
105
  children: React.ReactNode,
98
- groupKey?: string,
106
+ groupKeys: string[] = [],
99
107
  groupOptions?: ScreenConfigWithParent<
100
108
  State,
101
109
  ScreenOptions,
@@ -138,7 +146,7 @@ const getRouteConfigsFromChildren = <
138
146
  }
139
147
 
140
148
  acc.push({
141
- keys: [groupKey, child.props.navigationKey],
149
+ keys: [...groupKeys, child.props.navigationKey],
142
150
  options: groupOptions,
143
151
  layout: groupLayout,
144
152
  props: child.props as RouteConfig<
@@ -168,7 +176,9 @@ const getRouteConfigsFromChildren = <
168
176
  acc.push(
169
177
  ...getRouteConfigsFromChildren<State, ScreenOptions, EventMap>(
170
178
  child.props.children as React.ReactNode,
171
- child.props.navigationKey,
179
+ child.props.navigationKey != null
180
+ ? [...groupKeys, child.props.navigationKey]
181
+ : groupKeys,
172
182
  // FIXME
173
183
  // @ts-expect-error: add validation
174
184
  child.type !== Group
@@ -276,9 +286,24 @@ const getRouteConfigsFromChildren = <
276
286
  return configs;
277
287
  };
278
288
 
279
- const getStateFromParams = (params: NavigatorRoute['params']) => {
280
- if (params?.state != null) {
281
- return params.state;
289
+ const getStateFromParams = (
290
+ params: NavigatorRoute['params'],
291
+ type: string
292
+ ): NavigationState | PartialState<NavigationState> | undefined => {
293
+ const state = params?.state;
294
+
295
+ if (isNavigationState(state)) {
296
+ if (state.type != null && state.type !== type) {
297
+ if (process.env.NODE_ENV !== 'production') {
298
+ console.error(
299
+ `The state passed in the params is for a navigator of type '${state.type}', but it was passed to a navigator of type '${type}'. This can happen if the state was meant for a different navigator. The state will be discarded.`
300
+ );
301
+ }
302
+
303
+ return undefined;
304
+ }
305
+
306
+ return state;
282
307
  } else if (typeof params?.screen === 'string' && params?.initial !== false) {
283
308
  return {
284
309
  routes: [
@@ -320,9 +345,14 @@ export function useNavigationBuilder<
320
345
  ) {
321
346
  const navigatorKey = useRegisterNavigator();
322
347
 
323
- const route = React.useContext(NavigationRouteContext) as
324
- | NavigatorRoute
325
- | undefined;
348
+ const route = React.use(NavigationRouteContext) as NavigatorRoute | undefined;
349
+
350
+ const consumedParams = React.use(ConsumedParamsContext);
351
+
352
+ const isNestedParamsConsumed =
353
+ typeof route?.params === 'object' && route.params != null
354
+ ? consumedParams?.has(route.params)
355
+ : false;
326
356
 
327
357
  const {
328
358
  children,
@@ -366,44 +396,7 @@ export function useNavigationBuilder<
366
396
  return original;
367
397
  });
368
398
 
369
- const screens = routeConfigs.reduce<
370
- Record<string, ScreenConfigWithParent<State, ScreenOptions, EventMap>>
371
- >((acc, config) => {
372
- if (config.props.name in acc) {
373
- throw new Error(
374
- `A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${config.props.name}')`
375
- );
376
- }
377
-
378
- acc[config.props.name] = config;
379
- return acc;
380
- }, {});
381
-
382
399
  const routeNames = routeConfigs.map((config) => config.props.name);
383
- const routeKeyList = routeNames.reduce<Record<string, React.Key | undefined>>(
384
- (acc, curr) => {
385
- acc[curr] = screens[curr].keys.map((key) => key ?? '').join(':');
386
- return acc;
387
- },
388
- {}
389
- );
390
- const routeParamList = routeNames.reduce<Record<string, object | undefined>>(
391
- (acc, curr) => {
392
- const { initialParams } = screens[curr].props;
393
- acc[curr] = initialParams;
394
- return acc;
395
- },
396
- {}
397
- );
398
- const routeGetIdList = routeNames.reduce<
399
- RouterConfigOptions['routeGetIdList']
400
- >(
401
- (acc, curr) =>
402
- Object.assign(acc, {
403
- [curr]: screens[curr].props.getId,
404
- }),
405
- {}
406
- );
407
400
 
408
401
  if (!routeNames.length) {
409
402
  throw new Error(
@@ -411,6 +404,31 @@ export function useNavigationBuilder<
411
404
  );
412
405
  }
413
406
 
407
+ const screens: Record<
408
+ string,
409
+ ScreenConfigWithParent<State, ScreenOptions, EventMap>
410
+ > = {};
411
+
412
+ const routeKeyList: Record<string, (string | undefined)[]> = {};
413
+ const routeParamList: Record<string, object | undefined> = {};
414
+ const routeGetIdList: RouterConfigOptions['routeGetIdList'] = {};
415
+
416
+ for (const config of routeConfigs) {
417
+ const name = config.props.name;
418
+
419
+ if (name in screens) {
420
+ throw new Error(
421
+ `A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${name}')`
422
+ );
423
+ }
424
+
425
+ screens[name] = config;
426
+ routeKeyList[name] = config.keys;
427
+ routeParamList[name] = config.props.initialParams;
428
+
429
+ Object.assign(routeGetIdList, { [name]: config.props.getId });
430
+ }
431
+
414
432
  const isStateValid = React.useCallback(
415
433
  (state: NavigationState | PartialState<NavigationState>) =>
416
434
  state.type === undefined || state.type === router.type,
@@ -418,7 +436,9 @@ export function useNavigationBuilder<
418
436
  );
419
437
 
420
438
  const isStateInitialized = React.useCallback(
421
- (state: NavigationState | PartialState<NavigationState> | undefined) =>
439
+ <T extends NavigationState>(
440
+ state: T | PartialState<T> | undefined
441
+ ): state is T =>
422
442
  state !== undefined && state.stale === false && isStateValid(state),
423
443
  [isStateValid]
424
444
  );
@@ -436,16 +456,26 @@ export function useNavigationBuilder<
436
456
  setKey,
437
457
  getKey,
438
458
  getIsInitial,
439
- } = React.useContext(NavigationStateContext);
459
+ } = React.use(NavigationStateContext);
440
460
 
441
- const stateCleanedUp = React.useRef(false);
461
+ const { onEmitEvent, getIsStateEmitted } = React.use(
462
+ NavigationBuilderContext
463
+ );
464
+
465
+ const stateCleanupRef = React.useRef<boolean>(false);
466
+ const lastStateRef = React.useRef<State | PartialState<State> | undefined>(
467
+ undefined
468
+ );
442
469
 
443
470
  const setState = useLatestCallback(
444
- (state: NavigationState | PartialState<NavigationState> | undefined) => {
445
- if (stateCleanedUp.current) {
471
+ (state: State | PartialState<State> | undefined) => {
472
+ if (stateCleanupRef.current) {
473
+ // Store the state locally in case the current navigator is in `Activity`
474
+ lastStateRef.current = state;
475
+
446
476
  // State might have been already cleaned up due to unmount
447
- // We do not want to expose API allowing to override this
448
- // This would lead to old data preservation on main navigator unmount
477
+ // We don't want to update `route.state` in parent
478
+ // Otherwise it will be reused if a new navigator gets mounted
449
479
  return;
450
480
  }
451
481
 
@@ -457,15 +487,36 @@ export function useNavigationBuilder<
457
487
  stateBeforeInitialization,
458
488
  initializedState,
459
489
  isFirstStateInitialization,
490
+ paramsUsedForInitialization,
460
491
  ] = React.useMemo((): [
461
492
  PartialState<State> | undefined,
462
493
  State | undefined,
463
494
  boolean,
495
+ object | undefined,
464
496
  ] => {
497
+ // If the state was already cleaned up, but we have it stored in ref,
498
+ // It likely got cleaned up due to `<Activity mode="hidden">`
499
+ // We should reuse this state to avoid remounting screens
500
+ if (
501
+ stateCleanupRef.current &&
502
+ lastStateRef.current &&
503
+ isStateValid(lastStateRef.current)
504
+ ) {
505
+ const state: State = isStateInitialized(lastStateRef.current)
506
+ ? lastStateRef.current
507
+ : router.getRehydratedState(lastStateRef.current, {
508
+ routeNames,
509
+ routeParamList,
510
+ routeGetIdList,
511
+ });
512
+
513
+ return [undefined, state, false, undefined];
514
+ }
515
+
465
516
  const initialRouteParamList = routeNames.reduce<
466
517
  Record<string, object | undefined>
467
518
  >((acc, curr) => {
468
- const { initialParams } = screens[curr].props;
519
+ const { initialParams } = screens[curr]?.props ?? {};
469
520
  const initialParamsFromParams =
470
521
  route?.params?.state == null &&
471
522
  route?.params?.initial !== false &&
@@ -494,7 +545,8 @@ export function useNavigationBuilder<
494
545
  !(
495
546
  typeof route?.params?.screen === 'string' &&
496
547
  route?.params?.initial !== false
497
- )
548
+ ) &&
549
+ !isNestedParamsConsumed
498
550
  ) {
499
551
  return [
500
552
  undefined,
@@ -504,28 +556,48 @@ export function useNavigationBuilder<
504
556
  routeGetIdList,
505
557
  }),
506
558
  true,
559
+ undefined,
507
560
  ];
508
561
  } else {
509
- const stateFromParams = getStateFromParams(route?.params);
510
- const stateBeforeInitialization = (stateFromParams ??
511
- currentState) as PartialState<State>;
512
- const hydratedState = router.getRehydratedState(
513
- stateBeforeInitialization,
514
- {
515
- routeNames,
516
- routeParamList: initialRouteParamList,
517
- routeGetIdList,
518
- }
519
- );
562
+ const paramsForState = isNestedParamsConsumed ? undefined : route?.params;
563
+ const stateFromParams = paramsForState
564
+ ? getStateFromParams(paramsForState, router.type)
565
+ : undefined;
566
+
567
+ const stateBeforeInitialization = (stateFromParams ?? currentState) as
568
+ | PartialState<State>
569
+ | undefined;
570
+
571
+ const hydratedState =
572
+ stateBeforeInitialization == null
573
+ ? router.getInitialState({
574
+ routeNames,
575
+ routeParamList: initialRouteParamList,
576
+ routeGetIdList,
577
+ })
578
+ : router.getRehydratedState(stateBeforeInitialization, {
579
+ routeNames,
580
+ routeParamList: initialRouteParamList,
581
+ routeGetIdList,
582
+ });
520
583
 
521
584
  if (
585
+ stateBeforeInitialization != null &&
586
+ isStateValid(stateBeforeInitialization) &&
522
587
  options.routeNamesChangeBehavior === 'lastUnhandled' &&
523
588
  doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)
524
589
  ) {
525
- return [stateBeforeInitialization, hydratedState, true];
590
+ return [stateBeforeInitialization, hydratedState, true, paramsForState];
526
591
  }
527
592
 
528
- return [undefined, hydratedState, false];
593
+ return [
594
+ undefined,
595
+ hydratedState,
596
+ false,
597
+ // Current state is already initialized
598
+ // So params weren't used, and need to be handled later
599
+ isStateInitialized(currentState) ? undefined : paramsForState,
600
+ ];
529
601
  }
530
602
  // We explicitly don't include routeNames, route.params etc. in the dep list
531
603
  // below. We want to avoid forcing a new state to be calculated in those cases
@@ -537,12 +609,22 @@ export function useNavigationBuilder<
537
609
 
538
610
  const previousRouteKeyListRef = React.useRef(routeKeyList);
539
611
 
540
- React.useEffect(() => {
612
+ React.useInsertionEffect(() => {
541
613
  previousRouteKeyListRef.current = routeKeyList;
542
614
  });
543
615
 
544
616
  const previousRouteKeyList = previousRouteKeyListRef.current;
545
617
 
618
+ // Names of the screens whose navigation key changed since the last render
619
+ const routeKeyChanges = Object.keys(routeKeyList).filter((name) => {
620
+ const current = routeKeyList[name];
621
+ const previous = previousRouteKeyList[name];
622
+
623
+ return (
624
+ current != null && previous != null && !isArrayEqual(current, previous)
625
+ );
626
+ });
627
+
546
628
  const [unhandledState, setUnhandledState] = React.useState<
547
629
  NavigationState | PartialState<NavigationState> | undefined
548
630
  >(stateBeforeInitialization);
@@ -570,10 +652,14 @@ export function useNavigationBuilder<
570
652
  let nextState: State = state;
571
653
  let shouldClearUnhandledState = false;
572
654
 
573
- // Previously unhandled state is now valid again
574
- // And current state no longer has any valid routes
575
- // We should reuse the unhandled state instead of re-calculating the state
576
- if (
655
+ if (unhandledState != null && !isStateValid(unhandledState)) {
656
+ // The stored unhandled state is for a different type of navigator
657
+ // It can't be used with this navigator, so we discard it
658
+ setUnhandledState(undefined);
659
+ } else if (
660
+ // Previously unhandled state is now valid again
661
+ // And current state no longer has any valid routes
662
+ // We should reuse the unhandled state instead of re-calculating the state
577
663
  unhandledState?.routes.every((r) => routeNames.includes(r.name)) &&
578
664
  state?.routes.every((r) => !routeNames.includes(r.name))
579
665
  ) {
@@ -588,71 +674,68 @@ export function useNavigationBuilder<
588
674
  );
589
675
  } else if (
590
676
  !isArrayEqual(state.routeNames, routeNames) ||
591
- !isRecordEqual(routeKeyList, previousRouteKeyList)
677
+ routeKeyChanges.length !== 0
592
678
  ) {
593
679
  // When the list of route names change, the router should handle it to remove invalid routes
594
680
  nextState = router.getStateForRouteNamesChange(state, {
595
681
  routeNames,
596
682
  routeParamList,
597
683
  routeGetIdList,
598
- routeKeyChanges: Object.keys(routeKeyList).filter(
599
- (name) =>
600
- name in previousRouteKeyList &&
601
- routeKeyList[name] !== previousRouteKeyList[name]
602
- ),
684
+ routeKeyChanges,
603
685
  });
604
686
  }
605
687
 
606
- const previousNestedParamsRef = React.useRef(route?.params);
688
+ let didConsumeNestedParams = route?.params === paramsUsedForInitialization;
607
689
 
608
- React.useEffect(() => {
609
- previousNestedParamsRef.current = route?.params;
610
- }, [route?.params]);
690
+ if (route?.params && !didConsumeNestedParams) {
691
+ let action: CommonActions.Action | undefined;
611
692
 
612
- if (route?.params) {
613
- const previousParams = previousNestedParamsRef.current;
693
+ if (isNavigationState(route.params.state) && !isNestedParamsConsumed) {
694
+ didConsumeNestedParams = true;
614
695
 
615
- let action: CommonActions.Action | undefined;
696
+ const stateFromParams = getStateFromParams(route.params, router.type);
616
697
 
617
- if (
618
- typeof route.params.state === 'object' &&
619
- route.params.state != null &&
620
- route.params !== previousParams
621
- ) {
622
- if (
623
- options.routeNamesChangeBehavior === 'lastUnhandled' &&
624
- doesStateHaveOnlyInvalidRoutes(route.params.state)
625
- ) {
626
- if (route.params.state !== unhandledState) {
627
- setUnhandledState(route.params.state);
698
+ if (stateFromParams != null) {
699
+ if (
700
+ options.routeNamesChangeBehavior === 'lastUnhandled' &&
701
+ doesStateHaveOnlyInvalidRoutes(stateFromParams)
702
+ ) {
703
+ if (stateFromParams !== unhandledState) {
704
+ setUnhandledState(stateFromParams);
705
+ }
706
+ } else {
707
+ // If the route was updated with new state, we should reset to it
708
+ action = CommonActions.reset(stateFromParams);
628
709
  }
629
- } else {
630
- // If the route was updated with new state, we should reset to it
631
- action = CommonActions.reset(route.params.state);
632
710
  }
633
711
  } else if (
634
712
  typeof route.params.screen === 'string' &&
635
713
  ((route.params.initial === false && isFirstStateInitialization) ||
636
- route.params !== previousParams)
714
+ !isNestedParamsConsumed)
637
715
  ) {
716
+ didConsumeNestedParams = true;
717
+
638
718
  if (
639
719
  options.routeNamesChangeBehavior === 'lastUnhandled' &&
640
720
  !routeNames.includes(route.params.screen)
641
721
  ) {
642
- const state = getStateFromParams(route.params);
722
+ const state = getStateFromParams(route.params, router.type);
643
723
 
644
724
  if (state != null && !deepEqual(state, unhandledState)) {
645
725
  setUnhandledState(state);
646
726
  }
647
727
  } else {
648
728
  // If the route was updated with new screen name and/or params, we should navigate there
649
- action = CommonActions.navigate({
650
- name: route.params.screen,
651
- params: route.params.params,
652
- path: route.params.path,
653
- merge: route.params.merge,
654
- pop: route.params.pop,
655
- });
729
+ action = {
730
+ type: 'NAVIGATE',
731
+ payload: {
732
+ name: route.params.screen,
733
+ params: route.params.params,
734
+ path: route.params.path,
735
+ merge: route.params.merge,
736
+ pop: route.params.pop,
737
+ },
738
+ } as const;
656
739
  }
657
740
  }
658
741
 
@@ -665,6 +748,18 @@ export function useNavigationBuilder<
665
748
  })
666
749
  : null;
667
750
 
751
+ if (
752
+ process.env.NODE_ENV !== 'production' &&
753
+ action != null &&
754
+ updatedState === null
755
+ ) {
756
+ const names = routeNames.map((name) => `'${name}'`).join(', ');
757
+
758
+ console.error(
759
+ `The 'state' or 'screen' passed in the params couldn't be applied to the navigator with the screens: ${names}. This can happen if the params contain names of screens that don't exist in the navigator. The navigation specified in the params will be ignored.`
760
+ );
761
+ }
762
+
668
763
  nextState =
669
764
  updatedState !== null
670
765
  ? router.getRehydratedState(updatedState, {
@@ -675,14 +770,22 @@ export function useNavigationBuilder<
675
770
  : nextState;
676
771
  }
677
772
 
678
- const shouldUpdate =
679
- state !== nextState ||
680
- typeof route?.params?.state === 'object' ||
681
- typeof route?.params?.screen === 'string';
773
+ React.useEffect(() => {
774
+ if (
775
+ consumedParams &&
776
+ didConsumeNestedParams &&
777
+ typeof route?.params === 'object' &&
778
+ route.params != null
779
+ ) {
780
+ consumedParams.set(route.params, true);
781
+ }
782
+ }, [consumedParams, didConsumeNestedParams, route?.params]);
783
+
784
+ const shouldUpdate = state !== nextState;
682
785
 
683
786
  useScheduleUpdate(() => {
684
787
  if (shouldUpdate) {
685
- // If the state needs to be updated, we'll schedule an update
788
+ // Schedule an update if the state needs to be updated
686
789
  setState(nextState);
687
790
 
688
791
  if (shouldClearUnhandledState) {
@@ -696,43 +799,59 @@ export function useNavigationBuilder<
696
799
  // So we override the state object we return to use the latest state as soon as possible
697
800
  state = nextState;
698
801
 
802
+ // Last state to reuse if component gets cleaned up due to `<Activity mode="hidden">`
803
+ React.useEffect(() => {
804
+ lastStateRef.current = state;
805
+ });
806
+
807
+ const lastNotifiedStateRef = React.useRef<State | null>(null);
808
+
699
809
  React.useEffect(() => {
700
810
  // In strict mode, React will double-invoke effects.
701
811
  // So we need to reset the flag if component was not unmounted
702
- stateCleanedUp.current = false;
812
+ stateCleanupRef.current = false;
703
813
 
704
814
  setKey(navigatorKey);
705
815
 
706
- if (!getIsInitial()) {
707
- // If it's not initial render, we need to update the state
708
- // This will make sure that our container gets notifier of state changes due to new mounts
816
+ if (
817
+ (!getIsInitial() || getIsStateEmitted()) &&
818
+ lastNotifiedStateRef.current !== state
819
+ ) {
820
+ // We need to notify the state update in these scenarios:
821
+ // 1. If it's not the initial render of the component containing the navigator
822
+ // 2. If the container has already emitted state before the navigator mounted
823
+ //
824
+ // This will make sure that the container gets notified of state changes due to new mounts
709
825
  // This is necessary for proper screen tracking, URL updates etc.
710
- setState(nextState);
826
+ //
827
+ // During hydration, a nested navigator may mount after the container's initial state event.
828
+ // Or mount could be delayed due to conditional rendering, suspense etc.
829
+ // So only checking for the initial render is not enough.
830
+ // We also need to propagate the navigator's initial state when it mounts later,
831
+ // so the container is notified that the nested state is now available.
832
+ //
833
+ // We only notify if the state is different from what we already notified
834
+ // Otherwise, this goes into a loop when inside `<Activity mode="hidden">`
835
+ setState(state);
836
+
837
+ lastNotifiedStateRef.current = state;
711
838
  }
712
839
 
713
840
  return () => {
714
841
  // We need to clean up state for this navigator on unmount
715
842
  if (getCurrentState() !== undefined && getKey() === navigatorKey) {
716
843
  setCurrentState(undefined);
717
- stateCleanedUp.current = true;
844
+ stateCleanupRef.current = true;
718
845
  }
846
+
847
+ // Reset so that StrictMode's second mount re-propagates state correctly.
848
+ // Without this, the guard above sees the same reference and skips setState,
849
+ // causing the initial state to be lost after cleanup wipes the container state.
850
+ lastNotifiedStateRef.current = null;
719
851
  };
720
852
  // eslint-disable-next-line react-hooks/exhaustive-deps
721
853
  }, []);
722
854
 
723
- // In some cases (e.g. route names change), internal state might have changed
724
- // But it hasn't been committed yet, so hasn't propagated to the sync external store
725
- // During this time, we need to return the internal state in `getState`
726
- // Otherwise it can result in inconsistent state during render in children
727
- // To avoid this, we use a ref for render phase, and immediately clear it on commit
728
- const stateRef = React.useRef<State | null>(state);
729
-
730
- stateRef.current = state;
731
-
732
- React.useLayoutEffect(() => {
733
- stateRef.current = null;
734
- });
735
-
736
855
  const getState = useLatestCallback((): State => {
737
856
  const currentState = getCurrentState();
738
857
 
@@ -743,8 +862,6 @@ export function useNavigationBuilder<
743
862
  );
744
863
  });
745
864
 
746
- const { onEmitEvent } = React.useContext(NavigationBuilderContext);
747
-
748
865
  const emitter = useEventEmitter<EventMapCore<State>>((e) => {
749
866
  const routeNames = [];
750
867
 
@@ -767,43 +884,48 @@ export function useNavigationBuilder<
767
884
  return;
768
885
  }
769
886
 
770
- const navigation = descriptors[route.key].navigation;
771
-
772
- const listeners = ([] as (((e: any) => void) | undefined)[])
773
- .concat(
774
- // Get an array of listeners for all screens + common listeners on navigator
775
- ...[
776
- screenListeners,
777
- ...routeNames.map((name) => {
778
- const { listeners } = screens[name].props;
779
- return listeners;
780
- }),
781
- ].map((listeners) => {
782
- const map =
783
- typeof listeners === 'function'
784
- ? listeners({ route: route as any, navigation })
785
- : listeners;
786
-
787
- return map
788
- ? Object.keys(map)
789
- .filter((type) => type === e.type)
790
- .map((type) => map?.[type])
791
- : undefined;
792
- })
793
- )
794
- // We don't want same listener to be called multiple times for same event
795
- // So we remove any duplicate functions from the array
796
- .filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
887
+ const hasPerScreenListeners = routeNames.some(
888
+ (name) => screens[name]?.props.listeners != null
889
+ );
797
890
 
798
- listeners.forEach((listener) => listener?.(e));
891
+ if (screenListeners != null || hasPerScreenListeners) {
892
+ const descriptor = descriptors[route.key];
799
893
 
800
- onEmitEvent({
801
- type: e.type,
802
- data: e.data,
803
- target: e.target,
804
- defaultPrevented: e.defaultPrevented,
805
- });
806
- });
894
+ if (descriptor == null) {
895
+ throw new Error(`Couldn't find a descriptor for route '${route.key}'.`);
896
+ }
897
+
898
+ const navigation = descriptor.navigation;
899
+
900
+ const listeners = ([] as (((e: any) => void) | undefined)[])
901
+ .concat(
902
+ // Get an array of listeners for all screens + common listeners on navigator
903
+ ...[
904
+ screenListeners,
905
+ ...routeNames.map((name) => {
906
+ const { listeners } = screens[name]?.props ?? {};
907
+ return listeners;
908
+ }),
909
+ ].map((listeners) => {
910
+ const map =
911
+ typeof listeners === 'function'
912
+ ? listeners({ route: route as any, navigation })
913
+ : listeners;
914
+
915
+ return map
916
+ ? Object.keys(map)
917
+ .filter((type) => type === e.type)
918
+ .map((type) => map?.[type])
919
+ : undefined;
920
+ })
921
+ )
922
+ // We don't want same listener to be called multiple times for same event
923
+ // So we remove any duplicate functions from the array
924
+ .filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
925
+
926
+ listeners.forEach((listener) => listener?.(e));
927
+ }
928
+ }, onEmitEvent);
807
929
 
808
930
  useFocusEvents({ state, emitter });
809
931
 
@@ -837,7 +959,7 @@ export function useNavigationBuilder<
837
959
  setState,
838
960
  });
839
961
 
840
- const onUnhandledActionParent = React.useContext(UnhandledActionContext);
962
+ const onUnhandledActionParent = React.use(UnhandledActionContext);
841
963
 
842
964
  const onUnhandledAction = useLatestCallback((action: NavigationAction) => {
843
965
  if (
@@ -882,9 +1004,9 @@ export function useNavigationBuilder<
882
1004
  onAction,
883
1005
  onUnhandledAction,
884
1006
  getState,
1007
+ state,
885
1008
  emitter,
886
1009
  router,
887
- stateRef,
888
1010
  });
889
1011
 
890
1012
  useFocusedListenersChildrenAdapter({
@@ -903,9 +1025,7 @@ export function useNavigationBuilder<
903
1025
  ScreenOptions,
904
1026
  EventMap
905
1027
  >({
906
- routes: router.getRoutesFromState
907
- ? router.getRoutesFromState(state)
908
- : state.routes,
1028
+ routes: state.routes,
909
1029
  screens,
910
1030
  navigation,
911
1031
  screenOptions,
@@ -921,13 +1041,13 @@ export function useNavigationBuilder<
921
1041
  emitter,
922
1042
  });
923
1043
 
924
- useCurrentRender({
925
- state,
926
- navigation,
927
- descriptors,
928
- });
929
-
930
1044
  const NavigationContent = useComponent((children: React.ReactNode) => {
1045
+ const focusedRoute = state.routes[state.index];
1046
+
1047
+ if (focusedRoute == null) {
1048
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
1049
+ }
1050
+
931
1051
  const element =
932
1052
  layout != null
933
1053
  ? layout({
@@ -941,8 +1061,13 @@ export function useNavigationBuilder<
941
1061
  return (
942
1062
  <NavigationMetaContext.Provider value={undefined}>
943
1063
  <NavigationHelpersContext.Provider value={navigation}>
944
- <NavigationStateListenerProvider state={state}>
945
- <PreventRemoveProvider>{element}</PreventRemoveProvider>
1064
+ <NavigationStateListenerProvider
1065
+ state={state}
1066
+ getState={navigation.getState}
1067
+ >
1068
+ <FocusedRouteKeyContext.Provider value={focusedRoute.key}>
1069
+ <PreventRemoveProvider>{element}</PreventRemoveProvider>
1070
+ </FocusedRouteKeyContext.Provider>
946
1071
  </NavigationStateListenerProvider>
947
1072
  </NavigationHelpersContext.Provider>
948
1073
  </NavigationMetaContext.Provider>