@react-navigation/stack 7.0.0-alpha.7 → 7.0.0-alpha.9

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 (58) hide show
  1. package/lib/commonjs/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
  2. package/lib/commonjs/TransitionConfigs/TransitionPresets.js.map +1 -1
  3. package/lib/commonjs/navigators/createStackNavigator.js +4 -0
  4. package/lib/commonjs/navigators/createStackNavigator.js.map +1 -1
  5. package/lib/commonjs/views/Header/Header.js.map +1 -1
  6. package/lib/commonjs/views/Header/HeaderContainer.js +1 -1
  7. package/lib/commonjs/views/Header/HeaderContainer.js.map +1 -1
  8. package/lib/commonjs/views/Screens.js.map +1 -1
  9. package/lib/commonjs/views/Stack/Card.js +17 -9
  10. package/lib/commonjs/views/Stack/Card.js.map +1 -1
  11. package/lib/commonjs/views/Stack/CardContainer.js +4 -5
  12. package/lib/commonjs/views/Stack/CardContainer.js.map +1 -1
  13. package/lib/commonjs/views/Stack/CardStack.js +32 -21
  14. package/lib/commonjs/views/Stack/CardStack.js.map +1 -1
  15. package/lib/commonjs/views/Stack/StackView.js +20 -26
  16. package/lib/commonjs/views/Stack/StackView.js.map +1 -1
  17. package/lib/module/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
  18. package/lib/module/TransitionConfigs/TransitionPresets.js.map +1 -1
  19. package/lib/module/navigators/createStackNavigator.js +4 -0
  20. package/lib/module/navigators/createStackNavigator.js.map +1 -1
  21. package/lib/module/views/Header/Header.js.map +1 -1
  22. package/lib/module/views/Header/HeaderContainer.js +2 -2
  23. package/lib/module/views/Header/HeaderContainer.js.map +1 -1
  24. package/lib/module/views/Screens.js.map +1 -1
  25. package/lib/module/views/Stack/Card.js +17 -9
  26. package/lib/module/views/Stack/Card.js.map +1 -1
  27. package/lib/module/views/Stack/CardContainer.js +5 -6
  28. package/lib/module/views/Stack/CardContainer.js.map +1 -1
  29. package/lib/module/views/Stack/CardStack.js +32 -21
  30. package/lib/module/views/Stack/CardStack.js.map +1 -1
  31. package/lib/module/views/Stack/StackView.js +20 -26
  32. package/lib/module/views/Stack/StackView.js.map +1 -1
  33. package/lib/typescript/src/navigators/createStackNavigator.d.ts +1 -1
  34. package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
  35. package/lib/typescript/src/types.d.ts +33 -3
  36. package/lib/typescript/src/types.d.ts.map +1 -1
  37. package/lib/typescript/src/views/Screens.d.ts +1 -0
  38. package/lib/typescript/src/views/Screens.d.ts.map +1 -1
  39. package/lib/typescript/src/views/Stack/Card.d.ts +1 -0
  40. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  41. package/lib/typescript/src/views/Stack/CardContainer.d.ts +2 -4
  42. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  43. package/lib/typescript/src/views/Stack/CardStack.d.ts +1 -3
  44. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  45. package/lib/typescript/src/views/Stack/StackView.d.ts +5 -77
  46. package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
  47. package/package.json +18 -18
  48. package/src/TransitionConfigs/CardStyleInterpolators.tsx +5 -5
  49. package/src/TransitionConfigs/TransitionPresets.tsx +2 -2
  50. package/src/navigators/createStackNavigator.tsx +4 -1
  51. package/src/types.tsx +34 -3
  52. package/src/views/Header/Header.tsx +2 -2
  53. package/src/views/Header/HeaderContainer.tsx +4 -4
  54. package/src/views/Screens.tsx +1 -0
  55. package/src/views/Stack/Card.tsx +32 -15
  56. package/src/views/Stack/CardContainer.tsx +6 -5
  57. package/src/views/Stack/CardStack.tsx +190 -161
  58. package/src/views/Stack/StackView.tsx +13 -12
@@ -52,6 +52,8 @@ type Props = {
52
52
  insets: EdgeInsets;
53
53
  state: StackNavigationState<ParamListBase>;
54
54
  descriptors: StackDescriptorMap;
55
+ // eslint-disable-next-line react/no-unused-prop-types
56
+ preloadedDescriptors: StackDescriptorMap;
55
57
  routes: Route<string>[];
56
58
  // eslint-disable-next-line react/no-unused-prop-types
57
59
  openingRouteKeys: string[];
@@ -62,7 +64,6 @@ type Props = {
62
64
  route: Route<string>;
63
65
  }) => Route<string> | undefined;
64
66
  renderHeader: (props: HeaderContainerProps) => React.ReactNode;
65
- renderScene: (props: { route: Route<string> }) => React.ReactNode;
66
67
  isParentHeaderShown: boolean;
67
68
  isParentModal: boolean;
68
69
  onTransitionStart: (
@@ -174,7 +175,7 @@ const getHeaderHeights = (
174
175
 
175
176
  const getDistanceFromOptions = (
176
177
  layout: Layout,
177
- descriptor: StackDescriptor,
178
+ descriptor: StackDescriptor | undefined,
178
179
  isRTL: boolean
179
180
  ) => {
180
181
  const {
@@ -190,7 +191,7 @@ const getDistanceFromOptions = (
190
191
  const getProgressFromGesture = (
191
192
  gesture: Animated.Value,
192
193
  layout: Layout,
193
- descriptor: StackDescriptor,
194
+ descriptor: StackDescriptor | undefined,
194
195
  isRTL: boolean
195
196
  ) => {
196
197
  const distance = getDistanceFromOptions(
@@ -229,15 +230,20 @@ export class CardStack extends React.Component<Props, State> {
229
230
  return null;
230
231
  }
231
232
 
232
- const gestures = props.routes.reduce<GestureValues>((acc, curr) => {
233
- const descriptor = props.descriptors[curr.key];
233
+ const gestures = [
234
+ ...props.routes,
235
+ ...props.state.preloadedRoutes,
236
+ ].reduce<GestureValues>((acc, curr) => {
237
+ const descriptor =
238
+ props.descriptors[curr.key] || props.preloadedDescriptors[curr.key];
234
239
  const { animationEnabled } = descriptor?.options || {};
235
240
 
236
241
  acc[curr.key] =
237
242
  state.gestures[curr.key] ||
238
243
  new Animated.Value(
239
- props.openingRouteKeys.includes(curr.key) &&
240
- animationEnabled !== false
244
+ (props.openingRouteKeys.includes(curr.key) &&
245
+ animationEnabled !== false) ||
246
+ props.state.preloadedRoutes.includes(curr)
241
247
  ? getDistanceFromOptions(
242
248
  state.layout,
243
249
  descriptor,
@@ -249,147 +255,156 @@ export class CardStack extends React.Component<Props, State> {
249
255
  return acc;
250
256
  }, {});
251
257
 
252
- const scenes = props.routes.map((route, index, self) => {
253
- const previousRoute = self[index - 1];
254
- const nextRoute = self[index + 1];
255
-
256
- const oldScene = state.scenes[index];
257
-
258
- const currentGesture = gestures[route.key];
259
- const previousGesture = previousRoute
260
- ? gestures[previousRoute.key]
261
- : undefined;
262
- const nextGesture = nextRoute ? gestures[nextRoute.key] : undefined;
263
-
264
- const descriptor =
265
- props.descriptors[route.key] ||
266
- state.descriptors[route.key] ||
267
- (oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR);
268
-
269
- const nextDescriptor =
270
- props.descriptors[nextRoute?.key] || state.descriptors[nextRoute?.key];
271
-
272
- const previousDescriptor =
273
- props.descriptors[previousRoute?.key] ||
274
- state.descriptors[previousRoute?.key];
275
-
276
- // When a screen is not the last, it should use next screen's transition config
277
- // Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
278
- // For example combining a slide and a modal transition would look wrong otherwise
279
- // With this approach, combining different transition styles in the same navigator mostly looks right
280
- // This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
281
- // but majority of the transitions look alright
282
- const optionsForTransitionConfig =
283
- index !== self.length - 1 &&
284
- nextDescriptor &&
285
- nextDescriptor.options.presentation !== 'transparentModal'
286
- ? nextDescriptor.options
287
- : descriptor.options;
288
-
289
- const defaultTransitionPreset =
290
- optionsForTransitionConfig.presentation === 'modal'
291
- ? ModalTransition
292
- : optionsForTransitionConfig.presentation === 'transparentModal'
293
- ? ModalFadeTransition
294
- : DefaultTransition;
295
-
296
- const {
297
- animationEnabled = Platform.OS !== 'web' &&
298
- Platform.OS !== 'windows' &&
299
- Platform.OS !== 'macos',
300
- gestureEnabled = Platform.OS === 'ios' && animationEnabled,
301
- gestureDirection = defaultTransitionPreset.gestureDirection,
302
- transitionSpec = defaultTransitionPreset.transitionSpec,
303
- cardStyleInterpolator = animationEnabled === false
304
- ? forNoAnimationCard
305
- : defaultTransitionPreset.cardStyleInterpolator,
306
- headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
307
- cardOverlayEnabled = (Platform.OS !== 'ios' &&
308
- optionsForTransitionConfig.presentation !== 'transparentModal') ||
309
- getIsModalPresentation(cardStyleInterpolator),
310
- } = optionsForTransitionConfig;
311
-
312
- const headerMode: StackHeaderMode =
313
- descriptor.options.headerMode ??
314
- (!(
315
- optionsForTransitionConfig.presentation === 'modal' ||
316
- optionsForTransitionConfig.presentation === 'transparentModal' ||
317
- nextDescriptor?.options.presentation === 'modal' ||
318
- nextDescriptor?.options.presentation === 'transparentModal' ||
319
- getIsModalPresentation(cardStyleInterpolator)
320
- ) &&
321
- Platform.OS === 'ios' &&
322
- descriptor.options.header === undefined
323
- ? 'float'
324
- : 'screen');
325
-
326
- const isRTL = props.direction === 'rtl';
327
-
328
- const scene = {
329
- route,
330
- descriptor: {
331
- ...descriptor,
332
- options: {
333
- ...descriptor.options,
334
- animationEnabled,
335
- cardOverlayEnabled,
336
- cardStyleInterpolator,
337
- gestureDirection,
338
- gestureEnabled,
339
- headerStyleInterpolator,
340
- transitionSpec,
341
- headerMode,
258
+ const scenes = [...props.routes, ...props.state.preloadedRoutes].map(
259
+ (route, index, self) => {
260
+ // For preloaded screens, we don't care about the previous and the next screen
261
+ const isPreloaded = props.state.preloadedRoutes.includes(route);
262
+ const previousRoute = isPreloaded ? undefined : self[index - 1];
263
+ const nextRoute = isPreloaded ? undefined : self[index + 1];
264
+
265
+ const oldScene = state.scenes[index];
266
+
267
+ const currentGesture = gestures[route.key];
268
+ const previousGesture = previousRoute
269
+ ? gestures[previousRoute.key]
270
+ : undefined;
271
+ const nextGesture = nextRoute ? gestures[nextRoute.key] : undefined;
272
+
273
+ const descriptor =
274
+ (isPreloaded ? props.preloadedDescriptors : props.descriptors)[
275
+ route.key
276
+ ] ||
277
+ state.descriptors[route.key] ||
278
+ (oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR);
279
+
280
+ const nextDescriptor =
281
+ nextRoute &&
282
+ (props.descriptors[nextRoute?.key] ||
283
+ state.descriptors[nextRoute?.key]);
284
+
285
+ const previousDescriptor =
286
+ previousRoute &&
287
+ (props.descriptors[previousRoute?.key] ||
288
+ state.descriptors[previousRoute?.key]);
289
+
290
+ // When a screen is not the last, it should use next screen's transition config
291
+ // Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
292
+ // For example combining a slide and a modal transition would look wrong otherwise
293
+ // With this approach, combining different transition styles in the same navigator mostly looks right
294
+ // This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
295
+ // but the majority of the transitions look alright
296
+ const optionsForTransitionConfig =
297
+ index !== self.length - 1 &&
298
+ nextDescriptor &&
299
+ nextDescriptor.options.presentation !== 'transparentModal'
300
+ ? nextDescriptor.options
301
+ : descriptor.options;
302
+
303
+ const defaultTransitionPreset =
304
+ optionsForTransitionConfig.presentation === 'modal'
305
+ ? ModalTransition
306
+ : optionsForTransitionConfig.presentation === 'transparentModal'
307
+ ? ModalFadeTransition
308
+ : DefaultTransition;
309
+
310
+ const {
311
+ animationEnabled = Platform.OS !== 'web' &&
312
+ Platform.OS !== 'windows' &&
313
+ Platform.OS !== 'macos',
314
+ gestureEnabled = Platform.OS === 'ios' && animationEnabled,
315
+ gestureDirection = defaultTransitionPreset.gestureDirection,
316
+ transitionSpec = defaultTransitionPreset.transitionSpec,
317
+ cardStyleInterpolator = animationEnabled === false
318
+ ? forNoAnimationCard
319
+ : defaultTransitionPreset.cardStyleInterpolator,
320
+ headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
321
+ cardOverlayEnabled = (Platform.OS !== 'ios' &&
322
+ optionsForTransitionConfig.presentation !== 'transparentModal') ||
323
+ getIsModalPresentation(cardStyleInterpolator),
324
+ } = optionsForTransitionConfig;
325
+
326
+ const headerMode: StackHeaderMode =
327
+ descriptor.options.headerMode ??
328
+ (!(
329
+ optionsForTransitionConfig.presentation === 'modal' ||
330
+ optionsForTransitionConfig.presentation === 'transparentModal' ||
331
+ nextDescriptor?.options.presentation === 'modal' ||
332
+ nextDescriptor?.options.presentation === 'transparentModal' ||
333
+ getIsModalPresentation(cardStyleInterpolator)
334
+ ) &&
335
+ Platform.OS === 'ios' &&
336
+ descriptor.options.header === undefined
337
+ ? 'float'
338
+ : 'screen');
339
+
340
+ const isRTL = props.direction === 'rtl';
341
+
342
+ const scene = {
343
+ route,
344
+ descriptor: {
345
+ ...descriptor,
346
+ options: {
347
+ ...descriptor.options,
348
+ animationEnabled,
349
+ cardOverlayEnabled,
350
+ cardStyleInterpolator,
351
+ gestureDirection,
352
+ gestureEnabled,
353
+ headerStyleInterpolator,
354
+ transitionSpec,
355
+ headerMode,
356
+ },
342
357
  },
343
- },
344
- progress: {
345
- current: getProgressFromGesture(
346
- currentGesture,
347
- state.layout,
348
- descriptor,
349
- isRTL
350
- ),
351
- next:
352
- nextGesture &&
353
- nextDescriptor?.options.presentation !== 'transparentModal'
358
+ progress: {
359
+ current: getProgressFromGesture(
360
+ currentGesture,
361
+ state.layout,
362
+ descriptor,
363
+ isRTL
364
+ ),
365
+ next:
366
+ nextGesture &&
367
+ nextDescriptor?.options.presentation !== 'transparentModal'
368
+ ? getProgressFromGesture(
369
+ nextGesture,
370
+ state.layout,
371
+ nextDescriptor,
372
+ isRTL
373
+ )
374
+ : undefined,
375
+ previous: previousGesture
354
376
  ? getProgressFromGesture(
355
- nextGesture,
377
+ previousGesture,
356
378
  state.layout,
357
- nextDescriptor,
379
+ previousDescriptor,
358
380
  isRTL
359
381
  )
360
382
  : undefined,
361
- previous: previousGesture
362
- ? getProgressFromGesture(
363
- previousGesture,
364
- state.layout,
365
- previousDescriptor,
366
- isRTL
367
- )
368
- : undefined,
369
- },
370
- __memo: [
371
- state.layout,
372
- descriptor,
373
- nextDescriptor,
374
- previousDescriptor,
375
- currentGesture,
376
- nextGesture,
377
- previousGesture,
378
- ],
379
- };
383
+ },
384
+ __memo: [
385
+ state.layout,
386
+ descriptor,
387
+ nextDescriptor,
388
+ previousDescriptor,
389
+ currentGesture,
390
+ nextGesture,
391
+ previousGesture,
392
+ ],
393
+ };
394
+
395
+ if (
396
+ oldScene &&
397
+ scene.__memo.every((it, i) => {
398
+ // @ts-expect-error: we haven't added __memo to the annotation to prevent usage elsewhere
399
+ return oldScene.__memo[i] === it;
400
+ })
401
+ ) {
402
+ return oldScene;
403
+ }
380
404
 
381
- if (
382
- oldScene &&
383
- scene.__memo.every((it, i) => {
384
- // @ts-expect-error: we haven't added __memo to the annotation to prevent usage elsewhere
385
- return oldScene.__memo[i] === it;
386
- })
387
- ) {
388
- return oldScene;
405
+ return scene;
389
406
  }
390
-
391
- return scene;
392
- });
407
+ );
393
408
 
394
409
  return {
395
410
  routes: props.routes,
@@ -504,7 +519,6 @@ export class CardStack extends React.Component<Props, State> {
504
519
  onOpenRoute,
505
520
  onCloseRoute,
506
521
  renderHeader,
507
- renderScene,
508
522
  isParentHeaderShown,
509
523
  isParentModal,
510
524
  onTransitionStart,
@@ -546,16 +560,16 @@ export class CardStack extends React.Component<Props, State> {
546
560
  detachPreviousScreen = options.presentation === 'transparentModal'
547
561
  ? false
548
562
  : getIsModalPresentation(options.cardStyleInterpolator)
549
- ? i !==
550
- findLastIndex(scenes, (scene) => {
551
- const { cardStyleInterpolator } = scene.descriptor.options;
552
-
553
- return (
554
- cardStyleInterpolator === forModalPresentationIOS ||
555
- cardStyleInterpolator?.name === 'forModalPresentationIOS'
556
- );
557
- })
558
- : true,
563
+ ? i !==
564
+ findLastIndex(scenes, (scene) => {
565
+ const { cardStyleInterpolator } = scene.descriptor.options;
566
+
567
+ return (
568
+ cardStyleInterpolator === forModalPresentationIOS ||
569
+ cardStyleInterpolator?.name === 'forModalPresentationIOS'
570
+ );
571
+ })
572
+ : true,
559
573
  } = options;
560
574
 
561
575
  if (detachPreviousScreen === false) {
@@ -599,10 +613,23 @@ export class CardStack extends React.Component<Props, State> {
599
613
  style={styles.container}
600
614
  onLayout={this.handleLayout}
601
615
  >
602
- {routes.map((route, index, self) => {
616
+ {[...routes, ...state.preloadedRoutes].map((route, index) => {
603
617
  const focused = focusedRoute.key === route.key;
604
618
  const gesture = gestures[route.key];
605
619
  const scene = scenes[index];
620
+ // It is possible that for a short period the route appears in both arrays.
621
+ // Particularly, if the screen is removed with `retain`, then it needs a moment to execute the animation.
622
+ // However, due to the router action, it immediately populates the `preloadedRoutes` array.
623
+ // Practically, the logic below takes care that it is rendered only once.
624
+ const isPreloaded =
625
+ state.preloadedRoutes.includes(route) && !routes.includes(route);
626
+ if (
627
+ state.preloadedRoutes.includes(route) &&
628
+ routes.includes(route) &&
629
+ index >= routes.length
630
+ ) {
631
+ return null;
632
+ }
606
633
 
607
634
  // For the screens that shouldn't be active, the value is 0
608
635
  // For those that should be active, but are not the top screen, the value is 1
@@ -614,17 +641,17 @@ export class CardStack extends React.Component<Props, State> {
614
641
  | 1
615
642
  | 2 = 1;
616
643
 
617
- if (index < self.length - activeScreensLimit - 1) {
644
+ if (index < routes.length - activeScreensLimit - 1 || isPreloaded) {
618
645
  // screen should be inactive because it is too deep in the stack
619
646
  isScreenActive = STATE_INACTIVE;
620
647
  } else {
621
- const sceneForActivity = scenes[self.length - 1];
648
+ const sceneForActivity = scenes[routes.length - 1];
622
649
  const outputValue =
623
- index === self.length - 1
650
+ index === routes.length - 1
624
651
  ? STATE_ON_TOP // the screen is on top after the transition
625
- : index >= self.length - activeScreensLimit
626
- ? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
627
- : STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
652
+ : index >= routes.length - activeScreensLimit
653
+ ? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
654
+ : STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
628
655
  isScreenActive = sceneForActivity
629
656
  ? sceneForActivity.progress.current.interpolate({
630
657
  inputRange: [0, 1 - EPSILON, 1],
@@ -638,6 +665,7 @@ export class CardStack extends React.Component<Props, State> {
638
665
  headerShown = true,
639
666
  headerTransparent,
640
667
  freezeOnBlur,
668
+ autoHideHomeIndicator,
641
669
  } = scene.descriptor.options;
642
670
 
643
671
  const safeAreaInsetTop = insets.top;
@@ -667,17 +695,18 @@ export class CardStack extends React.Component<Props, State> {
667
695
  return (
668
696
  <MaybeScreen
669
697
  key={route.key}
670
- style={StyleSheet.absoluteFill}
698
+ style={[StyleSheet.absoluteFill]}
671
699
  enabled={detachInactiveScreens}
672
700
  active={isScreenActive}
673
701
  freezeOnBlur={freezeOnBlur}
702
+ homeIndicatorHidden={autoHideHomeIndicator}
674
703
  pointerEvents="box-none"
675
704
  >
676
705
  <CardContainer
677
706
  index={index}
678
707
  interpolationIndex={interpolationIndex}
679
708
  modal={isModal}
680
- active={index === self.length - 1}
709
+ active={index === routes.length - 1}
681
710
  focused={focused}
682
711
  closing={closingRouteKeys.includes(route.key)}
683
712
  layout={layout}
@@ -699,13 +728,13 @@ export class CardStack extends React.Component<Props, State> {
699
728
  isFloatHeaderAbsolute && !headerTransparent
700
729
  }
701
730
  renderHeader={renderHeader}
702
- renderScene={renderScene}
703
731
  onOpenRoute={onOpenRoute}
704
732
  onCloseRoute={onCloseRoute}
705
733
  onTransitionStart={onTransitionStart}
706
734
  onTransitionEnd={onTransitionEnd}
707
735
  isNextScreenTransparent={isNextScreenTransparent}
708
736
  detachCurrentScreen={detachCurrentScreen}
737
+ preloaded={isPreloaded}
709
738
  />
710
739
  </MaybeScreen>
711
740
  );
@@ -7,6 +7,7 @@ import {
7
7
  type LocaleDirection,
8
8
  type ParamListBase,
9
9
  type Route,
10
+ type RouteProp,
10
11
  StackActions,
11
12
  type StackNavigationState,
12
13
  } from '@react-navigation/native';
@@ -15,6 +16,7 @@ import { StyleSheet, View } from 'react-native';
15
16
  import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
16
17
 
17
18
  import type {
19
+ StackDescriptor,
18
20
  StackDescriptorMap,
19
21
  StackNavigationConfig,
20
22
  StackNavigationHelpers,
@@ -32,6 +34,10 @@ type Props = StackNavigationConfig & {
32
34
  state: StackNavigationState<ParamListBase>;
33
35
  navigation: StackNavigationHelpers;
34
36
  descriptors: StackDescriptorMap;
37
+ describe: (
38
+ route: RouteProp<ParamListBase>,
39
+ placeholder: boolean
40
+ ) => StackDescriptor;
35
41
  };
36
42
 
37
43
  type State = {
@@ -299,17 +305,6 @@ export class StackView extends React.Component<Props, State> {
299
305
  return routes[index - 1];
300
306
  };
301
307
 
302
- private renderScene = ({ route }: { route: Route<string> }) => {
303
- const descriptor =
304
- this.state.descriptors[route.key] || this.props.descriptors[route.key];
305
-
306
- if (!descriptor) {
307
- return null;
308
- }
309
-
310
- return descriptor.render();
311
- };
312
-
313
308
  private renderHeader = (props: HeaderContainerProps) => {
314
309
  return <HeaderContainer {...props} />;
315
310
  };
@@ -434,6 +429,12 @@ export class StackView extends React.Component<Props, State> {
434
429
  const { routes, descriptors, openingRouteKeys, closingRouteKeys } =
435
430
  this.state;
436
431
 
432
+ const preloadedDescriptors =
433
+ state.preloadedRoutes.reduce<StackDescriptorMap>((acc, route) => {
434
+ acc[route.key] = acc[route.key] || this.props.describe(route, true);
435
+ return acc;
436
+ }, {});
437
+
437
438
  return (
438
439
  <GestureHandlerWrapper style={styles.container}>
439
440
  <SafeAreaProviderCompat>
@@ -456,12 +457,12 @@ export class StackView extends React.Component<Props, State> {
456
457
  onTransitionStart={this.handleTransitionStart}
457
458
  onTransitionEnd={this.handleTransitionEnd}
458
459
  renderHeader={this.renderHeader}
459
- renderScene={this.renderScene}
460
460
  state={state}
461
461
  descriptors={descriptors}
462
462
  onGestureStart={this.handleGestureStart}
463
463
  onGestureEnd={this.handleGestureEnd}
464
464
  onGestureCancel={this.handleGestureCancel}
465
+ preloadedDescriptors={preloadedDescriptors}
465
466
  {...rest}
466
467
  />
467
468
  )}