@react-navigation/core 7.22.0 → 7.23.0

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 (43) hide show
  1. package/lib/module/BaseNavigationContainer.js +2 -1
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/NavigationMetaContext.js +3 -3
  4. package/lib/module/PreventRemoveProvider.js +3 -4
  5. package/lib/module/PreventRemoveProvider.js.map +1 -1
  6. package/lib/module/getPathFromState.js +5 -5
  7. package/lib/module/getPathFromState.js.map +1 -1
  8. package/lib/module/getStateFromPath.js +1 -1
  9. package/lib/module/getStateFromPath.js.map +1 -1
  10. package/lib/module/isRecordEqual.js +1 -1
  11. package/lib/module/isRecordEqual.js.map +1 -1
  12. package/lib/module/queryString.js +71 -0
  13. package/lib/module/queryString.js.map +1 -0
  14. package/lib/module/useDescriptors.js +35 -10
  15. package/lib/module/useDescriptors.js.map +1 -1
  16. package/lib/module/useNavigationBuilder.js +1 -0
  17. package/lib/module/useNavigationBuilder.js.map +1 -1
  18. package/lib/module/usePreventRemove.js +1 -2
  19. package/lib/module/usePreventRemove.js.map +1 -1
  20. package/lib/module/useRegisterNavigator.js +1 -2
  21. package/lib/module/useRegisterNavigator.js.map +1 -1
  22. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  23. package/lib/typescript/src/NavigationMetaContext.d.ts +3 -3
  24. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  25. package/lib/typescript/src/isRecordEqual.d.ts.map +1 -1
  26. package/lib/typescript/src/queryString.d.ts +5 -0
  27. package/lib/typescript/src/queryString.d.ts.map +1 -0
  28. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  29. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  30. package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
  31. package/lib/typescript/src/useRegisterNavigator.d.ts.map +1 -1
  32. package/package.json +2 -4
  33. package/src/BaseNavigationContainer.tsx +4 -2
  34. package/src/NavigationMetaContext.tsx +3 -3
  35. package/src/PreventRemoveProvider.tsx +4 -10
  36. package/src/getPathFromState.tsx +3 -3
  37. package/src/getStateFromPath.tsx +1 -1
  38. package/src/isRecordEqual.tsx +3 -1
  39. package/src/queryString.ts +109 -0
  40. package/src/useDescriptors.tsx +94 -23
  41. package/src/useNavigationBuilder.tsx +1 -0
  42. package/src/usePreventRemove.tsx +1 -2
  43. package/src/useRegisterNavigator.tsx +2 -2
@@ -7,6 +7,8 @@ import type {
7
7
  } from '@react-navigation/routers';
8
8
  import * as React from 'react';
9
9
 
10
+ import { isArrayEqual } from './isArrayEqual';
11
+ import { isRecordEqual } from './isRecordEqual';
10
12
  import {
11
13
  type AddKeyedListener,
12
14
  type AddListener,
@@ -84,6 +86,31 @@ type Options<
84
86
  emitter: NavigationEventEmitter<EventMap>;
85
87
  };
86
88
 
89
+ type DescriptorCache<
90
+ State extends NavigationState,
91
+ ScreenOptions extends {},
92
+ EventMap extends EventMapBase,
93
+ ActionHelpers extends Record<string, () => void>,
94
+ > = Record<
95
+ string,
96
+ {
97
+ descriptor: Descriptor<
98
+ ScreenOptions,
99
+ NavigationProp<
100
+ ParamListBase,
101
+ string,
102
+ string | undefined,
103
+ State,
104
+ ScreenOptions,
105
+ EventMap
106
+ > &
107
+ ActionHelpers,
108
+ RouteProp<ParamListBase>
109
+ >;
110
+ deps: unknown[];
111
+ }
112
+ >;
113
+
87
114
  /**
88
115
  * Hook to create descriptor objects for the child routes.
89
116
  *
@@ -173,6 +200,10 @@ export function useDescriptors<
173
200
 
174
201
  const routes = useRouteCache(state.routes);
175
202
 
203
+ const cache = React.useMemo<{
204
+ current: DescriptorCache<State, ScreenOptions, EventMap, ActionHelpers>;
205
+ }>(() => ({ current: {} }), []);
206
+
176
207
  const getOptions = (
177
208
  route: RouteProp<ParamListBase, string>,
178
209
  navigation: NavigationProp<
@@ -223,7 +254,8 @@ export function useDescriptors<
223
254
  EventMap
224
255
  >,
225
256
  customOptions: ScreenOptions,
226
- routeState: NavigationState | PartialState<NavigationState> | undefined
257
+ routeState: NavigationState | PartialState<NavigationState> | undefined,
258
+ layout: ScreenLayout<ScreenOptions> | undefined
227
259
  ) => {
228
260
  const config = screens[route.name];
229
261
  const screen = config.props;
@@ -238,14 +270,6 @@ export function useDescriptors<
238
270
  return o;
239
271
  });
240
272
 
241
- const layout =
242
- // The `layout` prop passed to `Screen` elements,
243
- screen.layout ??
244
- // The `screenLayout` props passed to `Group` elements
245
- config.layout ??
246
- // The default `screenLayout` passed to the navigator
247
- screenLayout;
248
-
249
273
  let element = (
250
274
  <SceneView
251
275
  navigation={navigation}
@@ -279,31 +303,67 @@ export function useDescriptors<
279
303
  );
280
304
  };
281
305
 
306
+ const next: DescriptorCache<State, ScreenOptions, EventMap, ActionHelpers> =
307
+ {};
308
+
282
309
  const descriptors = routes.reduce<
283
310
  Record<
284
311
  string,
285
- Descriptor<
312
+ DescriptorCache<
313
+ State,
286
314
  ScreenOptions,
287
- NavigationProp<
288
- ParamListBase,
289
- string,
290
- string | undefined,
291
- State,
292
- ScreenOptions,
293
- EventMap
294
- > &
295
- ActionHelpers,
296
- RouteProp<ParamListBase>
297
- >
315
+ EventMap,
316
+ ActionHelpers
317
+ >[string]['descriptor']
298
318
  >
299
319
  >((acc, route, i) => {
300
320
  const navigation = navigations[route.key];
301
321
  const customOptions = getOptions(route, navigation, options[route.key]);
322
+ const routeState = state.routes[i].state;
323
+ const config = screens[route.name];
324
+ const screen = config.props;
325
+
326
+ const layout =
327
+ // The `layout` prop passed to `Screen` elements,
328
+ screen.layout ??
329
+ // The `screenLayout` props passed to `Group` elements
330
+ config.layout ??
331
+ // The default `screenLayout` passed to the navigator
332
+ screenLayout;
333
+
334
+ const deps = [
335
+ route,
336
+ navigation,
337
+ routeState,
338
+ screen.component,
339
+ screen.getComponent,
340
+ screen.children,
341
+ layout,
342
+ context,
343
+ theme,
344
+ getState,
345
+ setState,
346
+ ];
347
+
348
+ const previous = cache.current[route.key];
349
+
350
+ if (
351
+ previous &&
352
+ isArrayEqual(previous.deps, deps) &&
353
+ isRecordEqual(previous.descriptor.options, customOptions)
354
+ ) {
355
+ next[route.key] = previous;
356
+ acc[route.key] = previous.descriptor;
357
+
358
+ return acc;
359
+ }
360
+
302
361
  const element = render(
303
362
  route,
304
363
  navigation,
305
364
  customOptions,
306
- state.routes[i].state
365
+ routeState,
366
+ layout
307
367
  );
308
368
 
309
369
  acc[route.key] = {
@@ -316,9 +376,18 @@ export function useDescriptors<
316
376
  options: customOptions,
317
377
  };
318
378
 
379
+ next[route.key] = {
380
+ descriptor: acc[route.key],
381
+ deps,
382
+ };
383
+
319
384
  return acc;
320
385
  }, {});
321
386
 
387
+ React.useInsertionEffect(() => {
388
+ cache.current = next;
389
+ });
390
+
322
391
  /**
323
392
  * Create a descriptor object for a route.
324
393
  *
@@ -337,7 +406,9 @@ export function useDescriptors<
337
406
 
338
407
  const navigation = base;
339
408
  const customOptions = getOptions(route, navigation, {});
340
- const element = render(route, navigation, customOptions, undefined);
409
+ const config = screens[route.name];
410
+ const layout = config.props.layout ?? config.layout ?? screenLayout;
411
+ const element = render(route, navigation, customOptions, undefined, layout);
341
412
 
342
413
  return {
343
414
  route,
@@ -21,6 +21,7 @@ import { Group } from './Group';
21
21
  import { isArrayEqual } from './isArrayEqual';
22
22
  import { NavigationBuilderContext } from './NavigationBuilderContext';
23
23
  import { NavigationHelpersContext } from './NavigationHelpersContext';
24
+ // eslint-disable-next-line import-x/no-deprecated
24
25
  import { NavigationMetaContext } from './NavigationMetaContext';
25
26
  import { NavigationRouteContext } from './NavigationProvider';
26
27
  import { NavigationStateContext } from './NavigationStateContext';
@@ -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.useContext(SingleNavigatorContext);
13
13
 
14
14
  if (container === undefined) {