@react-navigation/native#Route TypeScript Examples
The following examples show how to use
@react-navigation/native#Route.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CardStack.tsx From nlw2-proffy with MIT License | 6 votes |
private handleHeaderLayout = ({
route,
height,
}: {
route: Route<string>;
height: number;
}) => {
this.setState(({ headerHeights }) => {
const previousHeight = headerHeights[route.key];
if (previousHeight === height) {
return null;
}
return {
headerHeights: {
...headerHeights,
[route.key]: height,
},
};
});
};
Example #2
Source File: CardStack.tsx From nlw2-proffy with MIT License | 6 votes |
private getPreviousScene = ({ route }: { route: Route<string> }) => {
const { getPreviousRoute } = this.props;
const { scenes } = this.state;
const previousRoute = getPreviousRoute({ route });
if (previousRoute) {
const previousScene = scenes.find(
(scene) => scene.route.key === previousRoute.key
);
return previousScene;
}
return undefined;
};
Example #3
Source File: CardStack.tsx From nlw2-proffy with MIT License | 6 votes |
getHeaderHeights = (
routes: Route<string>[],
insets: EdgeInsets,
descriptors: StackDescriptorMap,
layout: Layout,
previous: Record<string, number>
) => {
return routes.reduce<Record<string, number>>((acc, curr) => {
const { options = {} } = descriptors[curr.key] || {};
const style: any = StyleSheet.flatten(options.headerStyle || {});
const height =
typeof style.height === 'number' ? style.height : previous[curr.key];
const safeAreaInsets = {
...insets,
...options.safeAreaInsets,
};
const { headerStatusBarHeight = safeAreaInsets.top } = options;
acc[curr.key] =
typeof height === 'number'
? height
: getDefaultHeaderHeight(layout, headerStatusBarHeight);
return acc;
}, {});
}
Example #4
Source File: StackView.tsx From nlw2-proffy with MIT License | 6 votes |
private getGesturesEnabled = ({ route }: { route: Route<string> }) => {
const descriptor = this.state.descriptors[route.key];
if (descriptor) {
const { gestureEnabled, animationEnabled } = descriptor.options;
if (animationEnabled === false) {
// When animation is disabled, also disable gestures
// The gesture to dismiss a route will look weird when not animated
return false;
}
return gestureEnabled !== false;
}
return false;
};
Example #5
Source File: StackView.tsx From nlw2-proffy with MIT License | 6 votes |
private getPreviousRoute = ({ route }: { route: Route<string> }) => {
const { closingRouteKeys, replacingRouteKeys } = this.state;
const routes = this.state.routes.filter(
(r) =>
r.key === route.key ||
(!closingRouteKeys.includes(r.key) &&
!replacingRouteKeys.includes(r.key))
);
const index = routes.findIndex((r) => r.key === route.key);
return routes[index - 1];
};
Example #6
Source File: StackView.tsx From nlw2-proffy with MIT License | 6 votes |
private renderScene = ({ route }: { route: Route<string> }) => {
const descriptor =
this.state.descriptors[route.key] || this.props.descriptors[route.key];
if (!descriptor) {
return null;
}
return descriptor.render();
};
Example #7
Source File: StackView.tsx From nlw2-proffy with MIT License | 6 votes |
private handleOpenRoute = ({ route }: { route: Route<string> }) => {
const { state, navigation } = this.props;
const { closingRouteKeys, replacingRouteKeys } = this.state;
if (
closingRouteKeys.some((key) => key === route.key) &&
replacingRouteKeys.every((key) => key !== route.key) &&
state.routeNames.includes(route.name) &&
!state.routes.some((r) => r.key === route.key)
) {
// If route isn't present in current state, but was closing, assume that a close animation was cancelled
// So we need to add this route back to the state
navigation.navigate(route);
} else {
this.setState((state) => ({
routes: state.replacingRouteKeys.length
? state.routes.filter(
(r) => !state.replacingRouteKeys.includes(r.key)
)
: state.routes,
openingRouteKeys: state.openingRouteKeys.filter(
(key) => key !== route.key
),
closingRouteKeys: state.closingRouteKeys.filter(
(key) => key !== route.key
),
replacingRouteKeys: [],
}));
}
};
Example #8
Source File: StackView.tsx From nlw2-proffy with MIT License | 6 votes |
private handleCloseRoute = ({ route }: { route: Route<string> }) => {
const { state, navigation } = this.props;
if (state.routes.some((r) => r.key === route.key)) {
// If a route exists in state, trigger a pop
// This will happen in when the route was closed from the card component
// e.g. When the close animation triggered from a gesture ends
navigation.dispatch({
...StackActions.pop(),
source: route.key,
target: state.key,
});
} else {
// We need to clean up any state tracking the route and pop it immediately
this.setState((state) => ({
routes: state.routes.filter((r) => r.key !== route.key),
openingRouteKeys: state.openingRouteKeys.filter(
(key) => key !== route.key
),
closingRouteKeys: state.closingRouteKeys.filter(
(key) => key !== route.key
),
}));
}
};
Example #9
Source File: StackView.tsx From nlw2-proffy with MIT License | 6 votes |
private handleTransitionStart = (
{ route }: { route: Route<string> },
closing: boolean
) =>
this.props.navigation.emit({
type: 'transitionStart',
data: { closing },
target: route.key,
});
Example #10
Source File: StackView.tsx From nlw2-proffy with MIT License | 6 votes |
private handleTransitionEnd = (
{ route }: { route: Route<string> },
closing: boolean
) =>
this.props.navigation.emit({
type: 'transitionEnd',
data: { closing },
target: route.key,
});
Example #11
Source File: PreviousSceneContext.tsx From nlw2-proffy with MIT License | 5 votes |
PreviousSceneContext = React.createContext<
Scene<Route<string>> | undefined
>(undefined)
Example #12
Source File: StackView.tsx From nlw2-proffy with MIT License | 5 votes |
private handleGestureCancel = ({ route }: { route: Route<string> }) => {
this.props.navigation.emit({
type: 'gestureCancel',
target: route.key,
});
};
Example #13
Source File: StackView.tsx From nlw2-proffy with MIT License | 5 votes |
private handleGestureEnd = ({ route }: { route: Route<string> }) => {
this.props.navigation.emit({
type: 'gestureEnd',
target: route.key,
});
};
Example #14
Source File: StackView.tsx From nlw2-proffy with MIT License | 5 votes |
private handleGestureStart = ({ route }: { route: Route<string> }) => {
this.props.navigation.emit({
type: 'gestureStart',
target: route.key,
});
};
Example #15
Source File: StackView.tsx From nlw2-proffy with MIT License | 4 votes |
static getDerivedStateFromProps(
props: Readonly<Props>,
state: Readonly<State>
) {
// If there was no change in routes, we don't need to compute anything
if (
(props.state.routes === state.previousRoutes ||
isArrayEqual(
props.state.routes.map((r) => r.key),
state.previousRoutes.map((r) => r.key)
)) &&
state.routes.length
) {
let routes = state.routes;
let previousRoutes = state.previousRoutes;
let descriptors = props.descriptors;
let previousDescriptors = state.previousDescriptors;
if (props.descriptors !== state.previousDescriptors) {
descriptors = state.routes.reduce<StackDescriptorMap>((acc, route) => {
acc[route.key] =
props.descriptors[route.key] || state.descriptors[route.key];
return acc;
}, {});
previousDescriptors = props.descriptors;
}
if (props.state.routes !== state.previousRoutes) {
// if any route objects have changed, we should update them
const map = props.state.routes.reduce<Record<string, Route<string>>>(
(acc, route) => {
acc[route.key] = route;
return acc;
},
{}
);
routes = state.routes.map((route) => map[route.key] || route);
previousRoutes = props.state.routes;
}
return {
routes,
previousRoutes,
descriptors,
previousDescriptors,
};
}
// Here we determine which routes were added or removed to animate them
// We keep a copy of the route being removed in local state to be able to animate it
let routes =
props.state.index < props.state.routes.length - 1
? // Remove any extra routes from the state
// The last visible route should be the focused route, i.e. at current index
props.state.routes.slice(0, props.state.index + 1)
: props.state.routes;
// Now we need to determine which routes were added and removed
let {
openingRouteKeys,
closingRouteKeys,
replacingRouteKeys,
previousRoutes,
} = state;
const previousFocusedRoute = previousRoutes[previousRoutes.length - 1] as
| Route<string>
| undefined;
const nextFocusedRoute = routes[routes.length - 1];
const isAnimationEnabled = (key: string) => {
const descriptor = props.descriptors[key] || state.descriptors[key];
return descriptor ? descriptor.options.animationEnabled !== false : true;
};
const getAnimationTypeForReplace = (key: string) => {
const descriptor = props.descriptors[key] || state.descriptors[key];
return descriptor.options.animationTypeForReplace ?? 'push';
};
if (
previousFocusedRoute &&
previousFocusedRoute.key !== nextFocusedRoute.key
) {
// 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
if (!previousRoutes.some((r) => r.key === nextFocusedRoute.key)) {
// A new route has come to the focus, we treat this as a push
// A replace can also trigger this, the animation should look like push
if (
isAnimationEnabled(nextFocusedRoute.key) &&
!openingRouteKeys.includes(nextFocusedRoute.key)
) {
// In this case, we need to animate pushing the focused route
// We don't care about animating any other added routes because they won't be visible
openingRouteKeys = [...openingRouteKeys, nextFocusedRoute.key];
closingRouteKeys = closingRouteKeys.filter(
(key) => key !== nextFocusedRoute.key
);
replacingRouteKeys = replacingRouteKeys.filter(
(key) => key !== nextFocusedRoute.key
);
if (!routes.some((r) => r.key === previousFocusedRoute.key)) {
// The previous focused route isn't present in state, we treat this as a replace
openingRouteKeys = openingRouteKeys.filter(
(key) => key !== previousFocusedRoute.key
);
if (getAnimationTypeForReplace(nextFocusedRoute.key) === 'pop') {
closingRouteKeys = [
...closingRouteKeys,
previousFocusedRoute.key,
];
// By default, new routes have a push animation, so we add it to `openingRouteKeys` before
// But since user configured it to animate the old screen like a pop, we need to add this without animation
// So remove it from `openingRouteKeys` which will remove the animation
openingRouteKeys = openingRouteKeys.filter(
(key) => key !== nextFocusedRoute.key
);
// Keep the route being removed at the end to animate it out
routes = [...routes, previousFocusedRoute];
} else {
replacingRouteKeys = [
...replacingRouteKeys,
previousFocusedRoute.key,
];
closingRouteKeys = closingRouteKeys.filter(
(key) => key !== previousFocusedRoute.key
);
// Keep the old route in the state because it's visible under the new route, and removing it will feel abrupt
// We need to insert it just before the focused one (the route being pushed)
// After the push animation is completed, routes being replaced will be removed completely
routes = routes.slice();
routes.splice(routes.length - 1, 0, previousFocusedRoute);
}
}
}
} else if (!routes.some((r) => r.key === previousFocusedRoute.key)) {
// The previously focused route was removed, we treat this as a pop
if (
isAnimationEnabled(previousFocusedRoute.key) &&
!closingRouteKeys.includes(previousFocusedRoute.key)
) {
closingRouteKeys = [...closingRouteKeys, previousFocusedRoute.key];
// Sometimes a route can be closed before the opening animation finishes
// So we also need to remove it from the opening list
openingRouteKeys = openingRouteKeys.filter(
(key) => key !== previousFocusedRoute.key
);
replacingRouteKeys = replacingRouteKeys.filter(
(key) => key !== previousFocusedRoute.key
);
// Keep a copy of route being removed in the state to be able to animate it
routes = [...routes, previousFocusedRoute];
}
} else {
// Looks like some routes were re-arranged and no focused routes were added/removed
// i.e. the currently focused route already existed and the previously focused route still exists
// We don't know how to animate this
}
} else if (replacingRouteKeys.length || closingRouteKeys.length) {
// Keep the routes we are closing or replacing if animation is enabled for them
routes = routes.slice();
routes.splice(
routes.length - 1,
0,
...state.routes.filter(({ key }) =>
isAnimationEnabled(key)
? replacingRouteKeys.includes(key) || closingRouteKeys.includes(key)
: false
)
);
}
if (!routes.length) {
throw new Error(
'There should always be at least one route in the navigation state.'
);
}
const descriptors = routes.reduce<StackDescriptorMap>((acc, route) => {
acc[route.key] =
props.descriptors[route.key] || state.descriptors[route.key];
return acc;
}, {});
return {
routes,
previousRoutes: props.state.routes,
previousDescriptors: props.descriptors,
openingRouteKeys,
closingRouteKeys,
replacingRouteKeys,
descriptors,
};
}
Example #16
Source File: AnimatedTabBar.tsx From curved-bottom-navigation-bar with MIT License | 4 votes |
AnimatedTabBarComponent = (props: AnimatedTabBarProps) => {
// props
const {
navigation,
tabs,
descriptors,
state,
duration = DEFAULT_ITEM_ANIMATION_DURATION,
barColor = TAB_BAR_COLOR,
dotSize = SIZE_DOT,
barHeight = TAB_BAR_HEIGHT,
dotColor = TAB_BAR_COLOR,
titleShown = false,
barWidth,
} = props;
// variables
const {
routes,
index: navigationIndex,
key: navigationKey,
} = useMemo(() => {
return state;
}, [state]);
// reanimated
const selectedIndex = useSharedValue(0);
// callbacks
const getRouteTitle = useCallback(
(route: Route<string>) => {
const { options } = descriptors[route.key];
// eslint-disable-next-line no-nested-ternary
return options.tabBarLabel !== undefined &&
typeof options.tabBarLabel === 'string'
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
},
[descriptors]
);
const getRouteTabConfigs = useCallback(
(route: Route<string>) => {
return tabs[route.name];
},
[tabs]
);
const getRoutes = useCallback(() => {
return routes.map((route) => ({
key: route.key,
title: getRouteTitle(route),
...getRouteTabConfigs(route),
}));
}, [routes, getRouteTitle, getRouteTabConfigs]);
const handleSelectedIndexChange = useCallback(
(index: number) => {
const { key, name } = routes[index];
const event = navigation.emit({
type: 'tabPress',
target: key,
canPreventDefault: true,
});
if (!event.defaultPrevented) {
navigation.dispatch({
...CommonActions.navigate(name),
target: navigationKey,
});
}
},
[routes, navigation, navigationKey]
);
// effects
useEffect(() => {
selectedIndex.value = navigationIndex;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [navigationIndex]);
useAnimatedReaction(
() => selectedIndex.value,
(nextSelected, prevSelected) => {
if (nextSelected !== prevSelected) {
runOnJS(handleSelectedIndexChange)(nextSelected);
}
},
[selectedIndex, handleSelectedIndexChange]
);
// render
return (
<CurvedTabBar
isRtl={I18nManager.isRTL}
barWidth={barWidth}
titleShown={titleShown}
dotColor={dotColor}
barHeight={barHeight}
dotSize={dotSize}
tabBarColor={barColor}
selectedIndex={selectedIndex}
navigationIndex={navigationIndex}
routes={getRoutes()}
duration={duration}
/>
);
}
Example #17
Source File: StackNavigator.tsx From sellflow with MIT License | 4 votes |
export default function StackNavigator() {
let { authToken } = useAuth();
let { data: userData } = useGetAuthenticatedUser();
let { isRTL } = useTheme();
function getTabSceneName(route: Pick<Route<string>, 'key' | 'name'>) {
const routeName = getFocusedRouteNameFromRoute(route) || 'HomeTab';
return routeName;
}
return (
<Stack.Navigator
screenOptions={headerOptions}
headerMode="screen"
initialRouteName={'Home'}
>
<Stack.Screen
name="Home"
component={TabNavigator}
options={({ navigation, route }) => {
let tabScene = getTabSceneName(route);
if (tabScene === 'HomeTab') {
return {
title:
authToken && userData?.authenticatedUser.firstName
? `${t('Hello')}, ${userData.authenticatedUser.firstName}`
: t('Hello'),
headerLeft: () => <LocalizationPicker />,
headerRight: () => (
<HeaderIconButton
icon="cart"
onPress={() => navigation.navigate('ShoppingCart')}
/>
),
headerStyle: {
shadowColor: COLORS.transparent,
elevation: 0,
},
};
} else if (tabScene === 'WishlistTab') {
return {
headerLeft: () => null,
title: t('Wishlist'),
};
} else {
return authToken
? {
headerLeft: () => null,
title: t('My Profile'),
}
: {
headerLeft: () =>
!authToken && (
<HeaderIconButton
icon={isRTL ? 'chevron-right' : 'chevron-left'}
onPress={() => navigation.navigate('HomeTab')}
/>
),
title: '',
headerStyle: {
shadowColor: COLORS.transparent,
elevation: 0,
},
};
}
}}
/>
<Stack.Screen
name="Auth"
component={AuthScene}
options={() => ({
title: t('Welcome'),
headerStyle: {
shadowColor: COLORS.transparent,
elevation: 0,
},
})}
/>
<Stack.Screen
name="ForgotPassword"
component={ForgotPasswordScene}
options={() => ({
title: t('Forgot Password'),
cardStyle: {
backgroundColor: COLORS.white,
},
})}
/>
<Stack.Screen
name="AddressManagement"
component={AddressManagementScene}
options={() => ({
title: t('Manage Addresses'),
})}
/>
<Stack.Screen name="AddEditAddress" component={AddEditAddressScene} />
<Stack.Screen
name="EditProfile"
component={EditProfileScene}
options={() => ({
title: t('Edit Profile'),
})}
/>
<Stack.Screen
name="OrderHistory"
component={OrderHistoryScene}
options={() => ({
title: t('Order History'),
cardStyle: {
backgroundColor: COLORS.darkWhite,
},
})}
/>
<Stack.Screen
name="OrderDetails"
component={OrderDetailsScene}
options={() => ({
title: t('Order Details'),
})}
/>
<Stack.Screen
name="ProductDetails"
component={ProductDetailsScene}
options={({ navigation }) => ({
title: t('Product Details'),
headerRight: () => (
<HeaderIconButton
icon="cart"
onPress={() => navigation.navigate('ShoppingCart')}
/>
),
})}
/>
<Stack.Screen
name="ShoppingCart"
component={ShoppingCartScene}
options={() => ({
title: t('Shopping Cart'),
})}
/>
<Stack.Screen
name="ProductCollection"
component={ProductCollectionScene}
options={({ route }) => ({
title: route.params.collection.title,
})}
/>
<Stack.Screen
name="SearchResults"
component={SearchResultsScene}
options={() => ({
title: t('Search Results'),
})}
/>
<Stack.Screen
name="Checkout"
component={CheckoutScene}
options={() => ({
title: t('Checkout'),
})}
/>
<Stack.Screen name="WebView" component={WebViewScene} />
<Stack.Screen
name="OrderPlacedConfirmation"
component={OrderPlacedConfirmationScene}
options={() => ({
title: t('Order Placed'),
headerLeft: () => null,
})}
/>
</Stack.Navigator>
);
}