diff --git a/packages/stack/src/types.tsx b/packages/stack/src/types.tsx index 11d28e91..12ab0850 100644 --- a/packages/stack/src/types.tsx +++ b/packages/stack/src/types.tsx @@ -124,6 +124,8 @@ export type SceneDescriptor = { getComponent(): React.ComponentType; }; +export type SceneDescriptorMap = { [key: string]: SceneDescriptor | undefined }; + export type HeaderBackButtonProps = { disabled?: boolean; onPress: () => void; diff --git a/packages/stack/src/views/Stack/Stack.tsx b/packages/stack/src/views/Stack/Stack.tsx index ef67c0da..ddafc88f 100755 --- a/packages/stack/src/views/Stack/Stack.tsx +++ b/packages/stack/src/views/Stack/Stack.tsx @@ -21,9 +21,10 @@ import { Route, Layout, HeaderMode, - SceneDescriptor, NavigationProp, HeaderScene, + SceneDescriptorMap, + NavigationStackOptions, } from '../../types'; type ProgressValues = { @@ -33,7 +34,7 @@ type ProgressValues = { type Props = { mode: 'card' | 'modal'; navigation: NavigationProp; - descriptors: { [key: string]: SceneDescriptor }; + descriptors: SceneDescriptorMap; routes: Route[]; openingRoutes: string[]; closingRoutes: string[]; @@ -56,7 +57,7 @@ type Props = { type State = { routes: Route[]; - descriptors: { [key: string]: SceneDescriptor }; + descriptors: SceneDescriptorMap; scenes: HeaderScene[]; progress: ProgressValues; layout: Layout; @@ -135,11 +136,14 @@ export default class Stack extends React.Component { const progress = props.routes.reduce( (acc, curr) => { + const descriptor = props.descriptors[curr.key]; + acc[curr.key] = state.progress[curr.key] || new Animated.Value( props.openingRoutes.includes(curr.key) && - props.descriptors[curr.key].options.animationEnabled !== false + descriptor && + descriptor.options.animationEnabled !== false ? 0 : 1 ); @@ -264,15 +268,21 @@ export default class Stack extends React.Component { previous: { index: number }; }) => { const { onTransitionStart, descriptors } = this.props; - const options = descriptors[route.key].options; + const descriptor = descriptors[route.key]; onTransitionStart && onTransitionStart(current, previous); - options.onTransitionStart && options.onTransitionStart(); + + descriptor && + descriptor.options.onTransitionStart && + descriptor.options.onTransitionStart(); }; private handleTransitionEnd = ({ route }: { route: Route }) => { - const options = this.props.descriptors[route.key].options; - options.onTransitionEnd && options.onTransitionEnd(); + const descriptor = this.props.descriptors[route.key]; + + descriptor && + descriptor.options.onTransitionEnd && + descriptor.options.onTransitionEnd(); }; render() { @@ -298,7 +308,8 @@ export default class Stack extends React.Component { const { scenes, layout, progress, floatingHeaderHeights } = this.state; const focusedRoute = navigation.state.routes[navigation.state.index]; - const focusedOptions = descriptors[focusedRoute.key].options; + const focusedDescriptor = descriptors[focusedRoute.key]; + const focusedOptions = focusedDescriptor ? focusedDescriptor.options : {}; let defaultTransitionPreset = mode === 'modal' ? ModalTransition : DefaultTransition; @@ -348,7 +359,9 @@ export default class Stack extends React.Component { transitionSpec = defaultTransitionPreset.transitionSpec, cardStyleInterpolator = defaultTransitionPreset.cardStyleInterpolator, headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator, - } = descriptor.options; + } = descriptor + ? descriptor.options + : ({} as NavigationStackOptions); return ( { @@ -91,9 +89,14 @@ class StackView extends React.Component { // We only need to animate routes if the focused route changed // Animating previous routes won't be visible coz the focused route is on top of everything - const isAnimationEnabled = (route: Route) => - (props.descriptors[route.key] || state.descriptors[route.key]).options - .animationEnabled !== false; + const isAnimationEnabled = (route: Route) => { + const descriptor = + props.descriptors[route.key] || state.descriptors[route.key]; + + return descriptor + ? descriptor.options.animationEnabled !== false + : true; + }; if (!previousRoutes.find(r => r.key === nextFocusedRoute.key)) { // A new route has come to the focus, we treat this as a push @@ -156,7 +159,7 @@ class StackView extends React.Component { return acc; }, - {} as Descriptors + {} as SceneDescriptorMap ); return { @@ -209,7 +212,13 @@ class StackView extends React.Component { }; private renderScene = ({ route }: { route: Route }) => { - const descriptor = this.state.descriptors[route.key]; + const descriptor = + this.state.descriptors[route.key] || this.props.descriptors[route.key]; + + if (!descriptor) { + return null; + } + const { navigation, getComponent } = descriptor; const SceneComponent = getComponent();