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

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 (157) hide show
  1. package/lib/module/BaseNavigationContainer.js +4 -9
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/NavigationIndependentTree.js +12 -7
  4. package/lib/module/NavigationIndependentTree.js.map +1 -1
  5. package/lib/module/NavigationProvider.js +49 -0
  6. package/lib/module/NavigationProvider.js.map +1 -0
  7. package/lib/module/PreventRemoveProvider.js +1 -1
  8. package/lib/module/PreventRemoveProvider.js.map +1 -1
  9. package/lib/module/SceneView.js.map +1 -1
  10. package/lib/module/StaticNavigation.js +32 -21
  11. package/lib/module/StaticNavigation.js.map +1 -1
  12. package/lib/module/createNavigationContainerRef.js.map +1 -1
  13. package/lib/module/getActionFromState.js +3 -2
  14. package/lib/module/getActionFromState.js.map +1 -1
  15. package/lib/module/getPathFromState.js +1 -1
  16. package/lib/module/getPathFromState.js.map +1 -1
  17. package/lib/module/getStateFromPath.js +3 -3
  18. package/lib/module/getStateFromPath.js.map +1 -1
  19. package/lib/module/index.js +1 -2
  20. package/lib/module/index.js.map +1 -1
  21. package/lib/module/theming/ThemeContext.js.map +1 -1
  22. package/lib/module/theming/ThemeProvider.js.map +1 -1
  23. package/lib/module/theming/useTheme.js +1 -1
  24. package/lib/module/theming/useTheme.js.map +1 -1
  25. package/lib/module/types.js +41 -0
  26. package/lib/module/types.js.map +1 -1
  27. package/lib/module/useChildListeners.js +2 -4
  28. package/lib/module/useChildListeners.js.map +1 -1
  29. package/lib/module/useDescriptors.js +5 -9
  30. package/lib/module/useDescriptors.js.map +1 -1
  31. package/lib/module/useEventEmitter.js +9 -20
  32. package/lib/module/useEventEmitter.js.map +1 -1
  33. package/lib/module/useFocusEvents.js +1 -1
  34. package/lib/module/useFocusEvents.js.map +1 -1
  35. package/lib/module/useNavigation.js +31 -8
  36. package/lib/module/useNavigation.js.map +1 -1
  37. package/lib/module/useNavigationBuilder.js +10 -12
  38. package/lib/module/useNavigationBuilder.js.map +1 -1
  39. package/lib/module/useNavigationCache.js +18 -11
  40. package/lib/module/useNavigationCache.js.map +1 -1
  41. package/lib/module/useNavigationHelpers.js +2 -14
  42. package/lib/module/useNavigationHelpers.js.map +1 -1
  43. package/lib/module/useNavigationState.js +42 -9
  44. package/lib/module/useNavigationState.js.map +1 -1
  45. package/lib/module/useOnAction.js +2 -7
  46. package/lib/module/useOnAction.js.map +1 -1
  47. package/lib/module/useOnGetState.js +1 -1
  48. package/lib/module/useOnGetState.js.map +1 -1
  49. package/lib/module/useOnPreventRemove.js +1 -1
  50. package/lib/module/useOnPreventRemove.js.map +1 -1
  51. package/lib/module/useRoute.js +23 -5
  52. package/lib/module/useRoute.js.map +1 -1
  53. package/lib/module/useScheduleUpdate.js +1 -2
  54. package/lib/module/useScheduleUpdate.js.map +1 -1
  55. package/lib/module/useSyncState.js +25 -9
  56. package/lib/module/useSyncState.js.map +1 -1
  57. package/lib/module/utilities.js +2 -0
  58. package/lib/module/utilities.js.map +1 -0
  59. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  60. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  61. package/lib/typescript/src/NavigationProvider.d.ts +44 -0
  62. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -0
  63. package/lib/typescript/src/SceneView.d.ts +1 -1
  64. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  65. package/lib/typescript/src/StaticNavigation.d.ts +231 -80
  66. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  67. package/lib/typescript/src/createNavigationContainerRef.d.ts +2 -2
  68. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  69. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  70. package/lib/typescript/src/index.d.ts +2 -3
  71. package/lib/typescript/src/index.d.ts.map +1 -1
  72. package/lib/typescript/src/theming/ThemeContext.d.ts +2 -1
  73. package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
  74. package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -1
  75. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  76. package/lib/typescript/src/theming/useTheme.d.ts +1 -1
  77. package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
  78. package/lib/typescript/src/types.d.ts +188 -133
  79. package/lib/typescript/src/types.d.ts.map +1 -1
  80. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  81. package/lib/typescript/src/useDescriptors.d.ts +27 -109
  82. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  83. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  84. package/lib/typescript/src/useNavigation.d.ts +7 -5
  85. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  86. package/lib/typescript/src/useNavigationBuilder.d.ts +25 -114
  87. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  88. package/lib/typescript/src/useNavigationCache.d.ts +8 -22
  89. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  90. package/lib/typescript/src/useNavigationContainerRef.d.ts +2 -2
  91. package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
  92. package/lib/typescript/src/useNavigationHelpers.d.ts +3 -11
  93. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  94. package/lib/typescript/src/useNavigationState.d.ts +10 -3
  95. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  96. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  97. package/lib/typescript/src/useRoute.d.ts +8 -2
  98. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  99. package/lib/typescript/src/useRouteCache.d.ts +12 -3
  100. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  101. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  102. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  103. package/lib/typescript/src/utilities.d.ts +99 -0
  104. package/lib/typescript/src/utilities.d.ts.map +1 -0
  105. package/package.json +7 -7
  106. package/src/BaseNavigationContainer.tsx +3 -9
  107. package/src/NavigationIndependentTree.tsx +17 -9
  108. package/src/NavigationProvider.tsx +64 -0
  109. package/src/PreventRemoveProvider.tsx +1 -1
  110. package/src/SceneView.tsx +1 -7
  111. package/src/StaticNavigation.tsx +372 -134
  112. package/src/createNavigationContainerRef.tsx +2 -1
  113. package/src/getActionFromState.tsx +4 -2
  114. package/src/getPathFromState.tsx +6 -5
  115. package/src/getStateFromPath.tsx +11 -11
  116. package/src/index.tsx +8 -4
  117. package/src/theming/ThemeContext.tsx +3 -3
  118. package/src/theming/ThemeProvider.tsx +2 -1
  119. package/src/theming/useTheme.tsx +1 -1
  120. package/src/types.tsx +392 -243
  121. package/src/useChildListeners.tsx +3 -2
  122. package/src/useDescriptors.tsx +11 -17
  123. package/src/useEventEmitter.tsx +14 -31
  124. package/src/useFocusEvents.tsx +1 -1
  125. package/src/useNavigation.tsx +57 -14
  126. package/src/useNavigationBuilder.tsx +10 -13
  127. package/src/useNavigationCache.tsx +40 -18
  128. package/src/useNavigationContainerRef.tsx +2 -2
  129. package/src/useNavigationHelpers.tsx +2 -19
  130. package/src/useNavigationState.tsx +90 -19
  131. package/src/useOnAction.tsx +1 -12
  132. package/src/useOnGetState.tsx +1 -1
  133. package/src/useOnPreventRemove.tsx +1 -1
  134. package/src/useRoute.tsx +52 -7
  135. package/src/useScheduleUpdate.tsx +1 -2
  136. package/src/useSyncState.tsx +28 -13
  137. package/src/utilities.tsx +122 -0
  138. package/lib/module/DeprecatedNavigationInChildContext.js +0 -9
  139. package/lib/module/DeprecatedNavigationInChildContext.js.map +0 -1
  140. package/lib/module/NavigationContext.js +0 -8
  141. package/lib/module/NavigationContext.js.map +0 -1
  142. package/lib/module/NavigationRouteContext.js +0 -9
  143. package/lib/module/NavigationRouteContext.js.map +0 -1
  144. package/lib/module/useClientLayoutEffect.js +0 -9
  145. package/lib/module/useClientLayoutEffect.js.map +0 -1
  146. package/lib/typescript/src/DeprecatedNavigationInChildContext.d.ts +0 -6
  147. package/lib/typescript/src/DeprecatedNavigationInChildContext.d.ts.map +0 -1
  148. package/lib/typescript/src/NavigationContext.d.ts +0 -8
  149. package/lib/typescript/src/NavigationContext.d.ts.map +0 -1
  150. package/lib/typescript/src/NavigationRouteContext.d.ts +0 -7
  151. package/lib/typescript/src/NavigationRouteContext.d.ts.map +0 -1
  152. package/lib/typescript/src/useClientLayoutEffect.d.ts +0 -6
  153. package/lib/typescript/src/useClientLayoutEffect.d.ts.map +0 -1
  154. package/src/DeprecatedNavigationInChildContext.tsx +0 -6
  155. package/src/NavigationContext.tsx +0 -11
  156. package/src/NavigationRouteContext.tsx +0 -9
  157. package/src/useClientLayoutEffect.tsx +0 -10
@@ -6,18 +6,19 @@ import type { ListenerMap } from './NavigationBuilderContext';
6
6
  * Hook which lets child navigators add action listeners.
7
7
  */
8
8
  export function useChildListeners() {
9
- const { current: listeners } = React.useRef<{
9
+ const listeners = React.useRef<{
10
10
  [K in keyof ListenerMap]: ListenerMap[K][];
11
11
  }>({
12
12
  action: [],
13
13
  focus: [],
14
- });
14
+ }).current;
15
15
 
16
16
  const addListener = React.useCallback(
17
17
  <T extends keyof ListenerMap>(type: T, listener: ListenerMap[T]) => {
18
18
  listeners[type].push(listener);
19
19
 
20
20
  let removed = false;
21
+
21
22
  return () => {
22
23
  const index = listeners[type].indexOf(listener);
23
24
 
@@ -12,8 +12,7 @@ import {
12
12
  type AddListener,
13
13
  NavigationBuilderContext,
14
14
  } from './NavigationBuilderContext';
15
- import { NavigationContext } from './NavigationContext';
16
- import { NavigationRouteContext } from './NavigationRouteContext';
15
+ import { NavigationProvider } from './NavigationProvider';
17
16
  import { SceneView } from './SceneView';
18
17
  import { ThemeContext } from './theming/ThemeContext';
19
18
  import type {
@@ -23,6 +22,7 @@ import type {
23
22
  NavigationProp,
24
23
  RouteConfig,
25
24
  RouteProp,
25
+ Theme,
26
26
  } from './types';
27
27
  import type { NavigationEventEmitter } from './useEventEmitter';
28
28
  import { useNavigationCache } from './useNavigationCache';
@@ -50,7 +50,7 @@ type ScreenLayout<ScreenOptions extends {}> = (props: {
50
50
  route: RouteProp<ParamListBase, string>;
51
51
  options: ScreenOptions;
52
52
  navigation: any;
53
- theme: ReactNavigation.Theme;
53
+ theme: Theme;
54
54
  children: React.ReactElement;
55
55
  }) => React.ReactElement;
56
56
 
@@ -59,7 +59,7 @@ type ScreenOptionsOrCallback<ScreenOptions extends {}> =
59
59
  | ((props: {
60
60
  route: RouteProp<ParamListBase, string>;
61
61
  navigation: any;
62
- theme: ReactNavigation.Theme;
62
+ theme: Theme;
63
63
  }) => ScreenOptions);
64
64
 
65
65
  type Options<
@@ -95,7 +95,7 @@ type Options<
95
95
  */
96
96
  export function useDescriptors<
97
97
  State extends NavigationState,
98
- ActionHelpers extends Record<string, () => void>,
98
+ ActionHelpers extends Record<string, (...args: any) => void>,
99
99
  ScreenOptions extends {},
100
100
  EventMap extends EventMapBase,
101
101
  >({
@@ -173,7 +173,6 @@ export function useDescriptors<
173
173
  navigation: NavigationProp<
174
174
  ParamListBase,
175
175
  string,
176
- string | undefined,
177
176
  State,
178
177
  ScreenOptions,
179
178
  EventMap
@@ -212,7 +211,6 @@ export function useDescriptors<
212
211
  navigation: NavigationProp<
213
212
  ParamListBase,
214
213
  string,
215
- string | undefined,
216
214
  State,
217
215
  ScreenOptions,
218
216
  EventMap
@@ -268,11 +266,9 @@ export function useDescriptors<
268
266
 
269
267
  return (
270
268
  <NavigationBuilderContext.Provider key={route.key} value={context}>
271
- <NavigationContext.Provider value={navigation}>
272
- <NavigationRouteContext.Provider value={route}>
273
- {element}
274
- </NavigationRouteContext.Provider>
275
- </NavigationContext.Provider>
269
+ <NavigationProvider navigation={navigation} route={route}>
270
+ {element}
271
+ </NavigationProvider>
276
272
  </NavigationBuilderContext.Provider>
277
273
  );
278
274
  };
@@ -285,12 +281,11 @@ export function useDescriptors<
285
281
  NavigationProp<
286
282
  ParamListBase,
287
283
  string,
288
- string | undefined,
289
284
  State,
290
285
  ScreenOptions,
291
- EventMap
292
- > &
293
- ActionHelpers,
286
+ EventMap,
287
+ ActionHelpers
288
+ >,
294
289
  RouteProp<ParamListBase>
295
290
  >
296
291
  >
@@ -306,7 +301,6 @@ export function useDescriptors<
306
301
 
307
302
  acc[route.key] = {
308
303
  route,
309
- // @ts-expect-error: it's missing action helpers, fix later
310
304
  navigation,
311
305
  render() {
312
306
  return element;
@@ -7,7 +7,7 @@ export type NavigationEventEmitter<T extends Record<string, any>> =
7
7
  create: (target: string) => EventConsumer<T>;
8
8
  };
9
9
 
10
- type Listeners = ((e: any) => void)[];
10
+ type Listeners = Set<(e: any) => void>;
11
11
 
12
12
  /**
13
13
  * Hook to manage the event system used by the navigator to notify screens of various events.
@@ -27,34 +27,18 @@ export function useEventEmitter<T extends Record<string, any>>(
27
27
 
28
28
  const create = React.useCallback((target: string) => {
29
29
  const removeListener = (type: string, callback: (data: any) => void) => {
30
- const callbacks = listeners.current[type]
31
- ? listeners.current[type][target]
32
- : undefined;
30
+ const callbacks = listeners.current[type]?.[target];
33
31
 
34
- if (!callbacks) {
35
- return;
36
- }
37
-
38
- const index = callbacks.indexOf(callback);
39
-
40
- if (index > -1) {
41
- callbacks.splice(index, 1);
42
- }
32
+ callbacks?.delete(callback);
43
33
  };
44
34
 
45
35
  const addListener = (type: string, callback: (data: any) => void) => {
46
- listeners.current[type] = listeners.current[type] || {};
47
- listeners.current[type][target] = listeners.current[type][target] || [];
48
- listeners.current[type][target].push(callback);
49
-
50
- let removed = false;
51
- return () => {
52
- // Prevent removing other listeners when unsubscribing same listener multiple times
53
- if (!removed) {
54
- removed = true;
55
- removeListener(type, callback);
56
- }
57
- };
36
+ listeners.current[type] ??= {};
37
+ listeners.current[type][target] ??= new Set();
38
+
39
+ listeners.current[type][target].add(callback);
40
+
41
+ return () => removeListener(type, callback);
58
42
  };
59
43
 
60
44
  return {
@@ -78,12 +62,11 @@ export function useEventEmitter<T extends Record<string, any>>(
78
62
  const items = listeners.current[type] || {};
79
63
 
80
64
  // Copy the current list of callbacks in case they are mutated during execution
81
- const callbacks =
82
- target !== undefined
83
- ? items[target]?.slice()
84
- : ([] as Listeners)
85
- .concat(...Object.keys(items).map((t) => items[t]))
86
- .filter((cb, i, self) => self.lastIndexOf(cb) === i);
65
+ const callbacks = new Set(
66
+ Object.values(target ? { [target]: items[target] } : items).flatMap(
67
+ (t) => (t ? Array.from(t) : [])
68
+ )
69
+ );
87
70
 
88
71
  const event: EventArg<any, any, any> = {
89
72
  get type() {
@@ -1,7 +1,7 @@
1
1
  import type { NavigationState } from '@react-navigation/routers';
2
2
  import * as React from 'react';
3
3
 
4
- import { NavigationContext } from './NavigationContext';
4
+ import { NavigationContext } from './NavigationProvider';
5
5
  import type { EventMapCore } from './types';
6
6
  import type { NavigationEventEmitter } from './useEventEmitter';
7
7
 
@@ -1,29 +1,72 @@
1
- import { type NavigationState } from '@react-navigation/routers';
2
1
  import * as React from 'react';
3
2
 
4
3
  import { NavigationContainerRefContext } from './NavigationContainerRefContext';
5
- import { NavigationContext } from './NavigationContext';
6
- import type { NavigationProp } from './types';
4
+ import {
5
+ NavigationContext,
6
+ NavigationRouteNameContext,
7
+ } from './NavigationProvider';
8
+ import type {
9
+ GenericNavigation,
10
+ NavigationListForNavigator,
11
+ NavigationListForNested,
12
+ RootNavigator,
13
+ RootParamList,
14
+ } from './types';
7
15
 
8
16
  /**
9
17
  * Hook to access the navigation prop of the parent screen anywhere.
10
18
  *
19
+ * If the route name of the current or one of the parents is specified,
20
+ * the navigation prop for that route is returned.
21
+ *
11
22
  * @returns Navigation prop of the parent screen.
12
23
  */
24
+ export function useNavigation(): GenericNavigation<RootParamList>;
25
+ export function useNavigation<
26
+ const Navigator = RootNavigator,
27
+ >(): NavigationListForNavigator<Navigator>[keyof NavigationListForNavigator<Navigator>];
13
28
  export function useNavigation<
14
- T = Omit<NavigationProp<ReactNavigation.RootParamList>, 'getState'> & {
15
- getState(): NavigationState | undefined;
16
- },
17
- >(): T {
18
- const root = React.useContext(NavigationContainerRefContext);
19
- const navigation = React.useContext(NavigationContext);
20
-
21
- if (navigation === undefined && root === undefined) {
29
+ const Navigator = RootNavigator,
30
+ const RouteName extends
31
+ keyof NavigationListForNested<Navigator> = keyof NavigationListForNested<Navigator>,
32
+ >(name: RouteName): NavigationListForNested<Navigator>[RouteName];
33
+ export function useNavigation(name?: string): unknown {
34
+ const root = React.use(NavigationContainerRefContext);
35
+ const navigation = React.use(NavigationContext);
36
+
37
+ if (name === undefined) {
38
+ if (navigation === undefined && root === undefined) {
39
+ throw new Error(
40
+ "Couldn't find a navigation object. Is your component inside NavigationContainer?"
41
+ );
42
+ }
43
+
44
+ return navigation ?? root;
45
+ }
46
+
47
+ const routeName = React.use(NavigationRouteNameContext);
48
+
49
+ // Generally, this condition isn't needed as `getParent(name)` works for current screen
50
+ // However, it'll throw if the hook is used in a preloaded screen
51
+ if (routeName === name) {
52
+ if (navigation === undefined) {
53
+ throw new Error(
54
+ `Couldn't find a navigation object for '${name}'. This is not expected.`
55
+ );
56
+ }
57
+
58
+ return navigation;
59
+ }
60
+
61
+ // We get parent first so that `getParent(name)` is not called in preloaded screens
62
+ // It's ok since `getParent` also works for current screen, so parent is not skipped
63
+ const parent = navigation?.getParent()?.getParent(name);
64
+
65
+ if (parent === undefined) {
22
66
  throw new Error(
23
- "Couldn't find a navigation object. Is your component inside NavigationContainer?"
67
+ `Couldn't find a navigation object for '${name}' in current or any parent screens. Is your component inside the correct screen?`
24
68
  );
25
69
  }
26
70
 
27
- // FIXME: Figure out a better way to do this
28
- return (navigation ?? root) as unknown as T;
71
+ return parent;
29
72
  }
@@ -21,7 +21,7 @@ import { isArrayEqual } from './isArrayEqual';
21
21
  import { isRecordEqual } from './isRecordEqual';
22
22
  import { NavigationHelpersContext } from './NavigationHelpersContext';
23
23
  import { NavigationMetaContext } from './NavigationMetaContext';
24
- import { NavigationRouteContext } from './NavigationRouteContext';
24
+ import { NavigationRouteContext } from './NavigationProvider';
25
25
  import { NavigationStateContext } from './NavigationStateContext';
26
26
  import { PreventRemoveProvider } from './PreventRemoveProvider';
27
27
  import { Screen } from './Screen';
@@ -35,7 +35,6 @@ import {
35
35
  } from './types';
36
36
  import { UnhandledActionContext } from './UnhandledActionContext';
37
37
  import { useChildListeners } from './useChildListeners';
38
- import { useClientLayoutEffect } from './useClientLayoutEffect';
39
38
  import { useComponent } from './useComponent';
40
39
  import { useCurrentRender } from './useCurrentRender';
41
40
  import { type ScreenConfigWithParent, useDescriptors } from './useDescriptors';
@@ -311,7 +310,6 @@ export function useNavigationBuilder<
311
310
  createRouter: RouterFactory<State, NavigationAction, RouterOptions>,
312
311
  options: DefaultNavigatorOptions<
313
312
  ParamListBase,
314
- string | undefined,
315
313
  State,
316
314
  ScreenOptions,
317
315
  EventMap,
@@ -331,7 +329,7 @@ export function useNavigationBuilder<
331
329
  screenOptions,
332
330
  screenLayout,
333
331
  screenListeners,
334
- UNSTABLE_router,
332
+ router: routerOverrides,
335
333
  ...rest
336
334
  } = options;
337
335
 
@@ -355,8 +353,8 @@ export function useNavigationBuilder<
355
353
 
356
354
  const original = createRouter(rest as unknown as RouterOptions);
357
355
 
358
- if (UNSTABLE_router != null) {
359
- const overrides = UNSTABLE_router(original);
356
+ if (routerOverrides != null) {
357
+ const overrides = routerOverrides(original);
360
358
 
361
359
  return {
362
360
  ...original,
@@ -520,7 +518,7 @@ export function useNavigationBuilder<
520
518
  );
521
519
 
522
520
  if (
523
- options.UNSTABLE_routeNamesChangeBehavior === 'lastUnhandled' &&
521
+ options.routeNamesChangeBehavior === 'lastUnhandled' &&
524
522
  doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)
525
523
  ) {
526
524
  return [stateBeforeInitialization, hydratedState, true];
@@ -553,7 +551,7 @@ export function useNavigationBuilder<
553
551
  // It's possible that they were absent due to conditional render
554
552
  // Store this state so we can reuse it if the routes change later
555
553
  if (
556
- options.UNSTABLE_routeNamesChangeBehavior === 'lastUnhandled' &&
554
+ options.routeNamesChangeBehavior === 'lastUnhandled' &&
557
555
  stateBeforeInitialization &&
558
556
  unhandledState !== stateBeforeInitialization
559
557
  ) {
@@ -621,7 +619,7 @@ export function useNavigationBuilder<
621
619
  route.params !== previousParams
622
620
  ) {
623
621
  if (
624
- options.UNSTABLE_routeNamesChangeBehavior === 'lastUnhandled' &&
622
+ options.routeNamesChangeBehavior === 'lastUnhandled' &&
625
623
  doesStateHaveOnlyInvalidRoutes(route.params.state)
626
624
  ) {
627
625
  if (route.params.state !== unhandledState) {
@@ -637,7 +635,7 @@ export function useNavigationBuilder<
637
635
  route.params !== previousParams)
638
636
  ) {
639
637
  if (
640
- options.UNSTABLE_routeNamesChangeBehavior === 'lastUnhandled' &&
638
+ options.routeNamesChangeBehavior === 'lastUnhandled' &&
641
639
  !routeNames.includes(route.params.screen)
642
640
  ) {
643
641
  const state = getStateFromParams(route.params);
@@ -730,7 +728,7 @@ export function useNavigationBuilder<
730
728
 
731
729
  stateRef.current = state;
732
730
 
733
- useClientLayoutEffect(() => {
731
+ React.useLayoutEffect(() => {
734
732
  stateRef.current = null;
735
733
  });
736
734
 
@@ -833,7 +831,7 @@ export function useNavigationBuilder<
833
831
 
834
832
  const onUnhandledAction = useLatestCallback((action: NavigationAction) => {
835
833
  if (
836
- options.UNSTABLE_routeNamesChangeBehavior === 'lastUnhandled' &&
834
+ options.routeNamesChangeBehavior === 'lastUnhandled' &&
837
835
  action.type === 'NAVIGATE' &&
838
836
  action.payload != null &&
839
837
  'name' in action.payload &&
@@ -871,7 +869,6 @@ export function useNavigationBuilder<
871
869
  NavigationAction,
872
870
  EventMap
873
871
  >({
874
- id: options.id,
875
872
  onAction,
876
873
  onUnhandledAction,
877
874
  getState,
@@ -8,6 +8,7 @@ import {
8
8
  import * as React from 'react';
9
9
 
10
10
  import { NavigationBuilderContext } from './NavigationBuilderContext';
11
+ import { NavigationContext } from './NavigationProvider';
11
12
  import type { NavigationHelpers, NavigationProp } from './types';
12
13
  import type { NavigationEventEmitter } from './useEventEmitter';
13
14
 
@@ -33,20 +34,25 @@ type NavigationItem<
33
34
  State extends NavigationState,
34
35
  ScreenOptions extends {},
35
36
  EventMap extends Record<string, any>,
37
+ ActionHelpers extends Record<string, (...args: any) => void>,
36
38
  > = NavigationProp<
37
39
  ParamListBase,
38
40
  string,
39
- string | undefined,
40
41
  State,
41
42
  ScreenOptions,
42
- EventMap
43
+ EventMap,
44
+ ActionHelpers
43
45
  >;
44
46
 
45
47
  type NavigationCache<
46
48
  State extends NavigationState,
47
49
  ScreenOptions extends {},
48
50
  EventMap extends Record<string, any>,
49
- > = Record<string, NavigationItem<State, ScreenOptions, EventMap>>;
51
+ ActionHelpers extends Record<string, (...args: any) => void>,
52
+ > = Record<
53
+ string,
54
+ NavigationItem<State, ScreenOptions, EventMap, ActionHelpers>
55
+ >;
50
56
 
51
57
  /**
52
58
  * Hook to cache navigation objects for each screen in the navigator.
@@ -57,7 +63,7 @@ export function useNavigationCache<
57
63
  State extends NavigationState,
58
64
  ScreenOptions extends {},
59
65
  EventMap extends Record<string, any>,
60
- ActionHelpers extends Record<string, () => void>,
66
+ ActionHelpers extends Record<string, (...args: any) => void>,
61
67
  >({
62
68
  state,
63
69
  getState,
@@ -66,12 +72,14 @@ export function useNavigationCache<
66
72
  router,
67
73
  emitter,
68
74
  }: Options<State, ScreenOptions, EventMap>) {
75
+ const parentNavigationHelpers = React.useContext(NavigationContext);
69
76
  const { stackRef } = React.useContext(NavigationBuilderContext);
70
77
 
71
78
  const base = React.useMemo((): NavigationItem<
72
79
  State,
73
80
  ScreenOptions,
74
- EventMap
81
+ EventMap,
82
+ ActionHelpers
75
83
  > &
76
84
  ActionHelpers => {
77
85
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -97,6 +105,7 @@ export function useNavigationCache<
97
105
  {}
98
106
  ) as ActionHelpers;
99
107
 
108
+ // @ts-expect-error: type of getParent does not match
100
109
  return {
101
110
  ...rest,
102
111
  ...helpers,
@@ -111,31 +120,40 @@ export function useNavigationCache<
111
120
  // Event listeners are not supported for placeholder screens
112
121
  },
113
122
  dispatch,
114
- getParent: (id?: string) => {
115
- if (id !== undefined && id === rest.getId()) {
116
- return base;
123
+ getParent: (routeName) => {
124
+ if (routeName !== undefined) {
125
+ throw new Error(
126
+ 'Getting parent by route name is not supported from a placeholder screen.'
127
+ );
117
128
  }
118
129
 
119
- return rest.getParent(id);
130
+ return parentNavigationHelpers;
120
131
  },
121
132
  setOptions: () => {
122
133
  throw new Error('Options cannot be set from a placeholder screen.');
123
134
  },
124
135
  isFocused: () => false,
125
136
  };
126
- }, [navigation, router.actionCreators]);
137
+ }, [parentNavigationHelpers, navigation, router.actionCreators]);
127
138
 
128
139
  // Cache object which holds navigation objects for each screen
129
140
  // We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
130
141
  // In reality, these deps will rarely change, if ever
131
142
  const cache = React.useMemo(
132
- () => ({ current: {} as NavigationCache<State, ScreenOptions, EventMap> }),
143
+ () => ({
144
+ current: {} as NavigationCache<
145
+ State,
146
+ ScreenOptions,
147
+ EventMap,
148
+ ActionHelpers
149
+ >,
150
+ }),
133
151
  // eslint-disable-next-line react-hooks/exhaustive-deps
134
- [base, getState, navigation, setOptions, emitter]
152
+ [base, getState, parentNavigationHelpers, navigation, setOptions, emitter]
135
153
  );
136
154
 
137
155
  cache.current = state.routes.reduce<
138
- NavigationCache<State, ScreenOptions, EventMap>
156
+ NavigationCache<State, ScreenOptions, EventMap, ActionHelpers>
139
157
  >((acc, route) => {
140
158
  const previous = cache.current[route.key];
141
159
 
@@ -201,14 +219,18 @@ export function useNavigationCache<
201
219
  // FIXME: too much work to fix the types for now
202
220
  ...(emitter.create(route.key) as any),
203
221
  dispatch: (thunk: Thunk) => withStack(() => dispatch(thunk)),
204
- getParent: (id?: string) => {
205
- if (id !== undefined && id === base.getId()) {
206
- // If the passed id is the same as the current navigation id,
207
- // we return the cached navigation object for the relevant route
222
+ getParent: (routeName) => {
223
+ if (routeName === route.name) {
224
+ // If the passed route name is the same as the current route's name,
225
+ // we return the cached navigation object for the route
208
226
  return acc[route.key];
209
227
  }
210
228
 
211
- return base.getParent(id);
229
+ if (routeName !== undefined) {
230
+ return parentNavigationHelpers?.getParent(routeName);
231
+ }
232
+
233
+ return parentNavigationHelpers;
212
234
  },
213
235
  setOptions: (options: object) => {
214
236
  setOptions((o) => ({
@@ -1,10 +1,10 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  import { createNavigationContainerRef } from './createNavigationContainerRef';
4
- import type { NavigationContainerRefWithCurrent } from './types';
4
+ import type { NavigationContainerRefWithCurrent, RootParamList } from './types';
5
5
 
6
6
  export function useNavigationContainerRef<
7
- ParamList extends {} = ReactNavigation.RootParamList,
7
+ ParamList extends {} = RootParamList,
8
8
  >(): NavigationContainerRefWithCurrent<ParamList> {
9
9
  const navigation =
10
10
  React.useRef<NavigationContainerRefWithCurrent<ParamList> | null>(null);
@@ -7,7 +7,7 @@ import {
7
7
  } from '@react-navigation/routers';
8
8
  import * as React from 'react';
9
9
 
10
- import { NavigationContext } from './NavigationContext';
10
+ import { NavigationContext } from './NavigationProvider';
11
11
  import { type NavigationHelpers, PrivateValueStore } from './types';
12
12
  import type { NavigationEventEmitter } from './useEventEmitter';
13
13
 
@@ -16,7 +16,6 @@ import type { NavigationEventEmitter } from './useEventEmitter';
16
16
  PrivateValueStore;
17
17
 
18
18
  type Options<State extends NavigationState, Action extends NavigationAction> = {
19
- id: string | undefined;
20
19
  onAction: (action: NavigationAction) => boolean;
21
20
  onUnhandledAction: (action: NavigationAction) => void;
22
21
  getState: () => State;
@@ -31,11 +30,10 @@ type Options<State extends NavigationState, Action extends NavigationAction> = {
31
30
  */
32
31
  export function useNavigationHelpers<
33
32
  State extends NavigationState,
34
- ActionHelpers extends Record<string, () => void>,
33
+ ActionHelpers extends Record<string, (...args: any) => void>,
35
34
  Action extends NavigationAction,
36
35
  EventMap extends Record<string, any>,
37
36
  >({
38
- id: navigatorId,
39
37
  onAction,
40
38
  onUnhandledAction,
41
39
  getState,
@@ -88,20 +86,6 @@ export function useNavigationHelpers<
88
86
  false
89
87
  );
90
88
  },
91
- getId: () => navigatorId,
92
- getParent: (id?: string) => {
93
- if (id !== undefined) {
94
- let current = navigationHelpers;
95
-
96
- while (current && id !== current.getId()) {
97
- current = current.getParent();
98
- }
99
-
100
- return current;
101
- }
102
-
103
- return parentNavigationHelpers;
104
- },
105
89
  getState: (): State => {
106
90
  // FIXME: Workaround for when the state is read during render
107
91
  // By this time, we haven't committed the new state yet
@@ -124,7 +108,6 @@ export function useNavigationHelpers<
124
108
  getState,
125
109
  onAction,
126
110
  onUnhandledAction,
127
- navigatorId,
128
111
  stateRef,
129
112
  ]);
130
113
  }