@react-navigation/core 8.0.0-alpha.36 → 8.0.0-alpha.38

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 (57) hide show
  1. package/lib/module/BaseNavigationContainer.js +2 -1
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/NavigationBuilderContext.js.map +1 -1
  4. package/lib/module/PreventRemoveProvider.js +1 -2
  5. package/lib/module/PreventRemoveProvider.js.map +1 -1
  6. package/lib/module/isRecordEqual.js +1 -1
  7. package/lib/module/isRecordEqual.js.map +1 -1
  8. package/lib/module/types.js.map +1 -1
  9. package/lib/module/useDescriptors.js +38 -11
  10. package/lib/module/useDescriptors.js.map +1 -1
  11. package/lib/module/useNavigationBuilder.js +19 -1
  12. package/lib/module/useNavigationBuilder.js.map +1 -1
  13. package/lib/module/useNavigationCache.js +4 -2
  14. package/lib/module/useNavigationCache.js.map +1 -1
  15. package/lib/module/useNavigationHelpers.js +3 -9
  16. package/lib/module/useNavigationHelpers.js.map +1 -1
  17. package/lib/module/useOnAction.js +17 -2
  18. package/lib/module/useOnAction.js.map +1 -1
  19. package/lib/module/useOptionsGetters.js +7 -1
  20. package/lib/module/useOptionsGetters.js.map +1 -1
  21. package/lib/module/usePreventRemove.js +1 -2
  22. package/lib/module/usePreventRemove.js.map +1 -1
  23. package/lib/module/useRegisterNavigator.js +1 -2
  24. package/lib/module/useRegisterNavigator.js.map +1 -1
  25. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  26. package/lib/typescript/src/NavigationBuilderContext.d.ts +1 -0
  27. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  28. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  29. package/lib/typescript/src/isRecordEqual.d.ts.map +1 -1
  30. package/lib/typescript/src/types.d.ts +2 -2
  31. package/lib/typescript/src/types.d.ts.map +1 -1
  32. package/lib/typescript/src/useDescriptors.d.ts +3 -2
  33. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  34. package/lib/typescript/src/useNavigationBuilder.d.ts +3 -35
  35. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  36. package/lib/typescript/src/useNavigationCache.d.ts +3 -2
  37. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  38. package/lib/typescript/src/useNavigationHelpers.d.ts +5 -36
  39. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  40. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  41. package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
  42. package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
  43. package/lib/typescript/src/useRegisterNavigator.d.ts.map +1 -1
  44. package/package.json +3 -4
  45. package/src/BaseNavigationContainer.tsx +4 -2
  46. package/src/NavigationBuilderContext.tsx +1 -0
  47. package/src/PreventRemoveProvider.tsx +2 -2
  48. package/src/isRecordEqual.tsx +3 -1
  49. package/src/types.tsx +3 -2
  50. package/src/useDescriptors.tsx +100 -23
  51. package/src/useNavigationBuilder.tsx +32 -1
  52. package/src/useNavigationCache.tsx +6 -1
  53. package/src/useNavigationHelpers.tsx +7 -15
  54. package/src/useOnAction.tsx +27 -2
  55. package/src/useOptionsGetters.tsx +7 -1
  56. package/src/usePreventRemove.tsx +1 -2
  57. package/src/useRegisterNavigator.tsx +2 -2
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@react-navigation/core",
3
3
  "description": "Core utilities for building navigators",
4
- "version": "8.0.0-alpha.36",
4
+ "version": "8.0.0-alpha.38",
5
5
  "keywords": [
6
6
  "react",
7
7
  "react-native",
@@ -45,9 +45,8 @@
45
45
  "clean": "del lib"
46
46
  },
47
47
  "dependencies": {
48
- "@react-navigation/routers": "^8.0.0-alpha.17",
48
+ "@react-navigation/routers": "^8.0.0-alpha.18",
49
49
  "fast-deep-equal": "^3.1.3",
50
- "nanoid": "^5.1.11",
51
50
  "react-is": "^19.2.6",
52
51
  "use-latest-callback": "^0.3.5",
53
52
  "warn-once": "^0.1.1"
@@ -88,5 +87,5 @@
88
87
  ]
89
88
  ]
90
89
  },
91
- "gitHead": "ac6baf188f7a456429a87b644053e765233f0151"
90
+ "gitHead": "904ba65a2938924d87658b7009a95698f93c7731"
92
91
  }
@@ -513,9 +513,9 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
513
513
  }, [state, isReady, emitter]);
514
514
 
515
515
  React.useEffect(() => {
516
- const hydratedState = getRootState();
517
-
518
516
  if (process.env.NODE_ENV !== 'production') {
517
+ const hydratedState = getRootState();
518
+
519
519
  if (hydratedState !== undefined) {
520
520
  const duplicateRouteNamesResult =
521
521
  checkDuplicateRouteNames(hydratedState);
@@ -535,6 +535,8 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
535
535
  emitter.emit({ type: 'state', data: { state } });
536
536
 
537
537
  if (!isFirstMountRef.current && onStateChangeRef.current) {
538
+ const hydratedState = getRootState();
539
+
538
540
  onStateChangeRef.current(hydratedState);
539
541
  }
540
542
 
@@ -61,6 +61,7 @@ export type ChildBeforeRemoveListener = (
61
61
  ) => boolean;
62
62
 
63
63
  type NavigationBuilderContextValue = {
64
+ canGoBack?: ((source?: string) => boolean) | undefined;
64
65
  onAction?:
65
66
  | ((action: NavigationAction, visitedNavigators?: Set<string>) => boolean)
66
67
  | undefined;
@@ -1,4 +1,3 @@
1
- import { nanoid } from 'nanoid/non-secure';
2
1
  import * as React from 'react';
3
2
  import useLatestCallback from 'use-latest-callback';
4
3
 
@@ -34,7 +33,8 @@ const transformPreventedRoutes = (
34
33
  * Component used for managing which routes have to be prevented from removal in native-stack.
35
34
  */
36
35
  export function PreventRemoveProvider({ children }: Props) {
37
- const [parentId] = React.useState(() => nanoid());
36
+ const parentId = React.useId();
37
+
38
38
  const [preventedRoutesMap, setPreventedRoutesMap] =
39
39
  React.useState<PreventedRoutesMap>(() => new Map());
40
40
 
@@ -16,5 +16,7 @@ export function isRecordEqual(
16
16
  return false;
17
17
  }
18
18
 
19
- return aKeys.every((key) => Object.is(a[key], b[key]));
19
+ return aKeys.every(
20
+ (key) => Object.hasOwn(b, key) && Object.is(a[key], b[key])
21
+ );
20
22
  }
package/src/types.tsx CHANGED
@@ -81,7 +81,7 @@ export type DefaultNavigatorOptions<
81
81
  layout?:
82
82
  | ((props: {
83
83
  state: State;
84
- navigation: NavigationHelpers<ParamList>;
84
+ navigation: NavigationHelpers<ParamList, State>;
85
85
  descriptors: Record<
86
86
  string,
87
87
  Descriptor<
@@ -470,8 +470,9 @@ type NavigationHelpersRoute<
470
470
 
471
471
  export type NavigationHelpers<
472
472
  ParamList extends ParamListBase,
473
+ State extends NavigationState = NavigationState<ParamList>,
473
474
  EventMap extends EventMapBase = {},
474
- > = NavigationHelpersCommon<ParamList> &
475
+ > = NavigationHelpersCommon<ParamList, State> &
475
476
  EventEmitter<EventMap> &
476
477
  NavigationHelpersRoute<ParamList, keyof ParamList> &
477
478
  PrivateValueStore<[ParamList, unknown, unknown, unknown]>;
@@ -8,6 +8,8 @@ import type {
8
8
  import * as React from 'react';
9
9
  import useLatestCallback from 'use-latest-callback';
10
10
 
11
+ import { isArrayEqual } from './isArrayEqual';
12
+ import { isRecordEqual } from './isRecordEqual';
11
13
  import {
12
14
  type AddKeyedListener,
13
15
  type AddListener,
@@ -74,10 +76,11 @@ type Options<
74
76
  ScreenConfigWithParent<State, ScreenOptions, EventMap>
75
77
  >;
76
78
  state: State;
77
- navigation: NavigationHelpers<ParamListBase>;
79
+ navigation: NavigationHelpers<ParamListBase, State>;
78
80
  screenOptions: ScreenOptionsOrCallback<ScreenOptions> | undefined;
79
81
  screenLayout: ScreenLayout<ScreenOptions> | undefined;
80
82
  onAction: (action: NavigationAction) => boolean;
83
+ canGoBack: (source?: string) => boolean;
81
84
  getState: () => State;
82
85
  setState: (state: State) => void;
83
86
  subscribe: (callback: () => void) => () => void;
@@ -88,6 +91,30 @@ type Options<
88
91
  emitter: NavigationEventEmitter<EventMap>;
89
92
  };
90
93
 
94
+ type DescriptorCache<
95
+ State extends NavigationState,
96
+ ScreenOptions extends {},
97
+ EventMap extends EventMapBase,
98
+ ActionHelpers extends Record<string, (...args: any) => void>,
99
+ > = Record<
100
+ string,
101
+ {
102
+ descriptor: Descriptor<
103
+ ScreenOptions,
104
+ NavigationProp<
105
+ ParamListBase,
106
+ string,
107
+ State,
108
+ ScreenOptions,
109
+ EventMap,
110
+ ActionHelpers
111
+ >,
112
+ RouteProp<ParamListBase>
113
+ >;
114
+ deps: unknown[];
115
+ }
116
+ >;
117
+
91
118
  /**
92
119
  * Hook to create descriptor objects for the child routes.
93
120
  *
@@ -108,6 +135,7 @@ export function useDescriptors<
108
135
  screenOptions,
109
136
  screenLayout,
110
137
  onAction,
138
+ canGoBack,
111
139
  getState,
112
140
  setState,
113
141
  subscribe,
@@ -136,6 +164,7 @@ export function useDescriptors<
136
164
  () => ({
137
165
  navigation,
138
166
  onAction,
167
+ canGoBack,
139
168
  addListener,
140
169
  addKeyedListener,
141
170
  onRouteFocus,
@@ -150,6 +179,7 @@ export function useDescriptors<
150
179
  [
151
180
  navigation,
152
181
  onAction,
182
+ canGoBack,
153
183
  addListener,
154
184
  addKeyedListener,
155
185
  onRouteFocus,
@@ -170,6 +200,7 @@ export function useDescriptors<
170
200
  ActionHelpers
171
201
  >({
172
202
  routes: state.routes,
203
+ canGoBack,
173
204
  getState,
174
205
  navigation,
175
206
  setOptions,
@@ -183,6 +214,10 @@ export function useDescriptors<
183
214
  () => state.routes[state.index]?.key
184
215
  );
185
216
 
217
+ const cache = React.useMemo<{
218
+ current: DescriptorCache<State, ScreenOptions, EventMap, ActionHelpers>;
219
+ }>(() => ({ current: {} }), []);
220
+
186
221
  const getOptions = (
187
222
  route: RouteProp<ParamListBase, string>,
188
223
  navigation: NavigationProp<
@@ -231,7 +266,8 @@ export function useDescriptors<
231
266
  EventMap
232
267
  >,
233
268
  customOptions: ScreenOptions,
234
- routeState: NavigationState | PartialState<NavigationState> | undefined
269
+ routeState: NavigationState | PartialState<NavigationState> | undefined,
270
+ layout: ScreenLayout<ScreenOptions> | undefined
235
271
  ) => {
236
272
  const config = screens[route.name];
237
273
  const screen = config?.props;
@@ -250,14 +286,6 @@ export function useDescriptors<
250
286
  return o;
251
287
  });
252
288
 
253
- const layout =
254
- // The `layout` prop passed to `Screen` elements,
255
- screen.layout ??
256
- // The `screenLayout` props passed to `Group` elements
257
- config?.layout ??
258
- // The default `screenLayout` passed to the navigator
259
- screenLayout;
260
-
261
289
  let element = (
262
290
  <SceneView
263
291
  navigation={navigation}
@@ -293,21 +321,18 @@ export function useDescriptors<
293
321
  );
294
322
  };
295
323
 
324
+ const next: DescriptorCache<State, ScreenOptions, EventMap, ActionHelpers> =
325
+ {};
326
+
296
327
  const descriptors = cachedRoutes.reduce<
297
328
  Record<
298
329
  string,
299
- Descriptor<
330
+ DescriptorCache<
331
+ State,
300
332
  ScreenOptions,
301
- NavigationProp<
302
- ParamListBase,
303
- string,
304
- State,
305
- ScreenOptions,
306
- EventMap,
307
- ActionHelpers
308
- >,
309
- RouteProp<ParamListBase>
310
- >
333
+ EventMap,
334
+ ActionHelpers
335
+ >[string]['descriptor']
311
336
  >
312
337
  >((acc, route, i) => {
313
338
  const navigation = navigations[route.key];
@@ -321,14 +346,56 @@ export function useDescriptors<
321
346
 
322
347
  const customOptions = getOptions(route, navigation, overrides);
323
348
 
349
+ const routeState = state.routes[i]?.state;
350
+ const config = screens[route.name];
351
+ const screen = config?.props;
352
+
353
+ const layout =
354
+ // The `layout` prop passed to `Screen` elements,
355
+ screen?.layout ??
356
+ // The `screenLayout` props passed to `Group` elements
357
+ config?.layout ??
358
+ // The default `screenLayout` passed to the navigator
359
+ screenLayout;
360
+
361
+ const deps = [
362
+ route,
363
+ navigation,
364
+ routeState,
365
+ screen?.component,
366
+ screen?.getComponent,
367
+ screen?.children,
368
+ layout,
369
+ context,
370
+ theme,
371
+ getFocusedRouteKey,
372
+ getState,
373
+ setState,
374
+ subscribe,
375
+ ];
376
+
377
+ const previous = cache.current[route.key];
378
+
379
+ if (
380
+ previous &&
381
+ isArrayEqual(previous.deps, deps) &&
382
+ isRecordEqual(previous.descriptor.options, customOptions)
383
+ ) {
384
+ next[route.key] = previous;
385
+ acc[route.key] = previous.descriptor;
386
+
387
+ return acc;
388
+ }
389
+
324
390
  const element = render(
325
391
  route,
326
392
  navigation,
327
393
  customOptions,
328
- state.routes[i]?.state
394
+ routeState,
395
+ layout
329
396
  );
330
397
 
331
- acc[route.key] = {
398
+ const descriptor = {
332
399
  route,
333
400
  navigation,
334
401
  render() {
@@ -337,8 +404,18 @@ export function useDescriptors<
337
404
  options: customOptions,
338
405
  };
339
406
 
407
+ acc[route.key] = descriptor;
408
+ next[route.key] = {
409
+ descriptor,
410
+ deps,
411
+ };
412
+
340
413
  return acc;
341
414
  }, {});
342
415
 
416
+ React.useInsertionEffect(() => {
417
+ cache.current = next;
418
+ });
419
+
343
420
  return descriptors;
344
421
  }
@@ -459,7 +459,11 @@ export function useNavigationBuilder<
459
459
  getIsInitial,
460
460
  } = React.use(NavigationStateContext);
461
461
 
462
- const { onEmitEvent, getIsStateEmitted } = useNavigationBuilderContext();
462
+ const {
463
+ onEmitEvent,
464
+ getIsStateEmitted,
465
+ canGoBack: canGoBackParent,
466
+ } = useNavigationBuilderContext();
463
467
 
464
468
  const mountStateRef = React.useRef<'initial' | 'mounted' | 'unmounted'>(
465
469
  'initial'
@@ -1003,6 +1007,31 @@ export function useNavigationBuilder<
1003
1007
  onUnhandledActionParent?.(action);
1004
1008
  });
1005
1009
 
1010
+ const canGoBack = useLatestCallback((source?: string) => {
1011
+ const state = getState();
1012
+
1013
+ return (
1014
+ router.getStateForAction(
1015
+ state,
1016
+ { ...CommonActions.goBack(), source },
1017
+ {
1018
+ routeNames: state.routeNames,
1019
+ routeParamList: {},
1020
+ routeGetIdList: {},
1021
+ }
1022
+ ) !== null ||
1023
+ canGoBackParent?.(
1024
+ // If the `source` belonged to the current navigator,
1025
+ // rewrite the `source` to the parent screen's key when checking
1026
+ // This mirrors the way actions bubble up to the parent
1027
+ source !== undefined && state.routes.some((r) => r.key === source)
1028
+ ? route?.key
1029
+ : source
1030
+ ) ||
1031
+ false
1032
+ );
1033
+ });
1034
+
1006
1035
  const navigation = useNavigationHelpers<
1007
1036
  State,
1008
1037
  ActionHelpers,
@@ -1011,6 +1040,7 @@ export function useNavigationBuilder<
1011
1040
  >({
1012
1041
  onAction,
1013
1042
  onUnhandledAction,
1043
+ canGoBack,
1014
1044
  getState,
1015
1045
  emitter,
1016
1046
  router,
@@ -1040,6 +1070,7 @@ export function useNavigationBuilder<
1040
1070
  screenOptions,
1041
1071
  screenLayout,
1042
1072
  onAction,
1073
+ canGoBack,
1043
1074
  getState,
1044
1075
  setState,
1045
1076
  subscribe,
@@ -19,8 +19,9 @@ type Options<
19
19
  > = {
20
20
  routes: State['routes'];
21
21
  getState: () => State;
22
- navigation: NavigationHelpers<ParamListBase> &
22
+ navigation: NavigationHelpers<ParamListBase, State> &
23
23
  Partial<NavigationProp<ParamListBase, string, any, any, any>>;
24
+ canGoBack: (source?: string) => boolean;
24
25
  setOptions: (
25
26
  cb: (
26
27
  options: Record<string, Partial<ScreenOptions> | undefined>
@@ -68,6 +69,7 @@ export function useNavigationCache<
68
69
  routes,
69
70
  getState,
70
71
  navigation,
72
+ canGoBack,
71
73
  setOptions,
72
74
  router,
73
75
  emitter,
@@ -89,6 +91,7 @@ export function useNavigationCache<
89
91
  getState,
90
92
  parentNavigation,
91
93
  navigation,
94
+ canGoBack,
92
95
  setOptions,
93
96
  router,
94
97
  emitter,
@@ -155,6 +158,7 @@ export function useNavigationCache<
155
158
  // FIXME: too much work to fix the types for now
156
159
  ...(emitter.create(route.key) as any),
157
160
  dispatch,
161
+ canGoBack: () => canGoBack(route.key),
158
162
  getParent: (routeName) => {
159
163
  if (routeName === route.name) {
160
164
  // If the passed route name is the same as the current route's name,
@@ -203,6 +207,7 @@ export function useNavigationCache<
203
207
  routes,
204
208
  getState,
205
209
  navigation,
210
+ canGoBack,
206
211
  router,
207
212
  withStackTrace,
208
213
  emitter,
@@ -19,6 +19,7 @@ PrivateValueStore;
19
19
  type Options<State extends NavigationState, Action extends NavigationAction> = {
20
20
  onAction: (action: NavigationAction) => boolean;
21
21
  onUnhandledAction: (action: NavigationAction) => void;
22
+ canGoBack: (source?: string) => boolean;
22
23
  getState: () => State;
23
24
  emitter: NavigationEventEmitter<any>;
24
25
  router: Router<State, Action>;
@@ -36,11 +37,13 @@ export function useNavigationHelpers<
36
37
  >({
37
38
  onAction,
38
39
  onUnhandledAction,
40
+ canGoBack,
39
41
  getState,
40
42
  emitter,
41
43
  router,
42
44
  }: Options<State, Action>) {
43
45
  const parentNavigationHelpers = React.use(NavigationContext);
46
+
44
47
  const { withStackTrace } = useNavigationBuilderContext();
45
48
 
46
49
  return React.useMemo(() => {
@@ -82,27 +85,16 @@ export function useNavigationHelpers<
82
85
  isFocused: parentNavigationHelpers
83
86
  ? parentNavigationHelpers.isFocused
84
87
  : () => true,
85
- canGoBack: () => {
86
- const state = getState();
87
-
88
- return (
89
- router.getStateForAction(state, CommonActions.goBack() as Action, {
90
- routeNames: state.routeNames,
91
- routeParamList: {},
92
- routeGetIdList: {},
93
- }) !== null ||
94
- parentNavigationHelpers?.canGoBack() ||
95
- false
96
- );
97
- },
88
+ canGoBack: () => canGoBack(),
98
89
  getState,
99
- } as NavigationHelpers<ParamListBase, EventMap> & ActionHelpers;
90
+ } as NavigationHelpers<ParamListBase, State, EventMap> & ActionHelpers;
100
91
 
101
92
  return navigationHelpers;
102
93
  }, [
103
- router,
94
+ router.actionCreators,
104
95
  parentNavigationHelpers,
105
96
  emitter.emit,
97
+ canGoBack,
106
98
  getState,
107
99
  onAction,
108
100
  onUnhandledAction,
@@ -166,19 +166,44 @@ export function useOnAction<State extends NavigationState>({
166
166
  }
167
167
  }
168
168
 
169
+ const isSourceInCurrentNavigator =
170
+ action.source !== undefined &&
171
+ state.routes.some((r) => r.key === action.source);
172
+
169
173
  if (onActionParent !== undefined) {
170
174
  // Bubble action to the parent if the current navigator didn't handle it
171
- if (onActionParent(action, visitedNavigators)) {
175
+ const parentAction =
176
+ isSourceInCurrentNavigator && key !== undefined
177
+ ? {
178
+ ...action,
179
+ // If the `source` belonged to the current navigator,
180
+ // rewrite the `source` to the parent screen's key when bubbling
181
+ // This will let parent handle it relative to the child that dispatched the action
182
+ source: key,
183
+ }
184
+ : action;
185
+
186
+ if (onActionParent(parentAction, visitedNavigators)) {
172
187
  return true;
173
188
  }
174
189
  }
175
190
 
176
191
  if (typeof action.target === 'string') {
177
192
  // If the action wasn't handled by current navigator or a parent navigator, let children handle it
193
+ const childAction = isSourceInCurrentNavigator
194
+ ? {
195
+ ...action,
196
+ // If the `source` belonged to the current navigator,
197
+ // remove it when targeting a child navigator
198
+ // So child navigators can handle it based on the focused screen
199
+ source: undefined,
200
+ }
201
+ : action;
202
+
178
203
  for (let i = actionListeners.length - 1; i >= 0; i--) {
179
204
  const listener = actionListeners[i];
180
205
 
181
- if (listener?.(action, visitedNavigators)) {
206
+ if (listener?.(childAction, visitedNavigators)) {
182
207
  return true;
183
208
  }
184
209
  }
@@ -80,6 +80,12 @@ export function useOptionsGetters({
80
80
  (key: string, getter: () => object | undefined | null) => {
81
81
  optionsGettersFromChildRef.current[key] = getter;
82
82
 
83
+ // Hidden screens may register without running their passive effects.
84
+ // Wait until the commit finishes before reporting their options.
85
+ if (onOptionsChange !== undefined) {
86
+ void Promise.resolve().then(onOptionsChange);
87
+ }
88
+
83
89
  return () => {
84
90
  // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
85
91
  delete optionsGettersFromChildRef.current[key];
@@ -87,7 +93,7 @@ export function useOptionsGetters({
87
93
  // Other getters and the focused route may still change during cleanup.
88
94
  // Wait until the commit finishes before reporting the remaining options.
89
95
  if (onOptionsChange !== undefined) {
90
- queueMicrotask(onOptionsChange);
96
+ void Promise.resolve().then(onOptionsChange);
91
97
  }
92
98
  };
93
99
  },
@@ -1,5 +1,4 @@
1
1
  import type { NavigationAction } from '@react-navigation/routers';
2
- import { nanoid } from 'nanoid/non-secure';
3
2
  import * as React from 'react';
4
3
  import useLatestCallback from 'use-latest-callback';
5
4
 
@@ -18,7 +17,7 @@ export function usePreventRemove(
18
17
  preventRemove: boolean,
19
18
  callback: (options: { data: { action: NavigationAction } }) => void
20
19
  ) {
21
- const [id] = React.useState(() => nanoid());
20
+ const id = React.useId();
22
21
 
23
22
  const navigation = useNavigation();
24
23
  const { key: routeKey } = useRoute();
@@ -1,4 +1,3 @@
1
- import { nanoid } from 'nanoid/non-secure';
2
1
  import * as React from 'react';
3
2
 
4
3
  import { SingleNavigatorContext } from './EnsureSingleNavigator';
@@ -8,7 +7,8 @@ import { SingleNavigatorContext } from './EnsureSingleNavigator';
8
7
  * This is used to prevent multiple navigators under a single container or screen.
9
8
  */
10
9
  export function useRegisterNavigator() {
11
- const [key] = React.useState(() => nanoid());
10
+ const key = React.useId();
11
+
12
12
  const container = React.use(SingleNavigatorContext);
13
13
 
14
14
  if (container === undefined) {