61FIT3MPR - Spring 2025
Lecture 05
Navigation and Routing
in React Native Ecosystem
Contents
• Understand the core concepts of Mobile Navigation and Web
Routing
• Master the installation and configuration within Expo
• Deep dive into Native Stack, Bottom Tabs, and Drawer navigators.
• Learn professional state management through Route Params.
What is Navigation?
• Navigation: the ability to move between different screens within an app.
• Allows users to interact with various app functionalities.
• Managing the "History" of the
user's journey.
• Handling transitions and gestures
(e.g., swiping back).
• Essential for UX: How does the
user get from Point A to Point B?
Web Routing and Mobile Navigation
• Web (URL-based):
Based on the address bar. Every page is a unique URL.
• Mobile (Stack-based):
Screens are layered on top of each other.
• State:
Mobile navigation is a "State" managed by the app, not just a string in the
browser.
React Navigation
• The "De-facto" Standard:
• It is the most widely adopted navigation library in the React Native
community.
• Extensibility & Flexibility:
• Uses a Pluggable Architecture: You only install what you need (Stack,
Tabs, or Drawer).
React Navigation
• Cross-Platform Consistency:
• Provides a unified API for iOS, Android, and Web.
• Automatically handles platform-specific behaviors (e.g., the "Push"
animation is different on iOS vs. Android).
• JS-based with Native Performance:
• Written in JavaScript for ease of use but leverages Native Primitives via
react-native-screens.
• This ensures smooth 60 FPS transitions while remaining easy to debug in
JavaScript.
Common Navigator Types
Common Navigator Types
• Native Stack Navigator (@react-navigation/native-stack)
• Behavior: Screens are "pushed" onto a stack. Only the top screen is
visible.
• Use Case: The most common pattern. Ideal for hierarchical navigation
(e.g., Home → Product List → Product Detail).
• Native Feel: Uses OS-native animations and gestures (like swipe-to-back
on iOS).
Common Navigator Types
• Bottom Tab Navigator (@react-navigation/bottom-tabs)
• Behavior:
A persistent bar at the bottom for quick switching between top-level screens.
• Use Case:
Main app entry points (e.g., Facebook’s News Feed, Notifications, and Menu).
• UX Note:
Keeps the most important sections
of the app just one tap away.
Common Navigator Types
• Drawer Navigator (@react-navigation/drawer)
• Behavior:
• A side menu that slides in from the left or right.
• Use Case:
• Overflow navigation for settings, user profiles,
or secondary features that don't fit in the Bottom Tab.
Expo Router
• Is a file-based router for React Native and web applications.
• Allowing to manage navigation between screens in your app.
• Allowing to move seamlessly between different parts of app's UI.
• Using the same components on multiple platforms (Android, iOS,
and web).
• When a file is added to the app directory, the file automatically
becomes a route in your navigation.
Features of Expo Router
• Native: Built on top of our powerful React Navigation suite, Expo
Router navigation is truly native and platform-optimized by
default.
• Shareable: Every screen in app is automatically deep linkable.
Making any route in app shareable with links.
• Offline-first: Apps are cached and run offline-first, with automatic
updates when publishing a new version. Handles all incoming
native URLs without a network connection or server.
• Optimized: Routes are automatically optimized with
lazy-evaluation in production, and deferred bundling in
development.
Features of Expo Router
• Iteration: Universal Fast Refresh across Android, iOS, along with
artifact memoization in the bundler to keep moving fast at scale.
• Universal: Android, iOS share a unified navigation structure, with
the ability to drop-down to platform-specific APIs at the route
level.
Core concepts of file-based routing in Expo Router
• All screens are files inside of app directory
o All navigation routes in the app are defined by the files and sub-directories
inside the app directory. Every file inside the app directory has a default
export that defines a distinct page in the app (except for the
special _layout files).
o Accordingly, directories inside app define groups of related screens
together as stacks, tabs, or in other arrangements.
• All screens have a URL
o All pages have a URL path that matches the file's location in
the app directory, which can be used as an app-specific deep link in a
native mobile app. This is what is meant by Expo Router supporting
"universal deep-linking". All screens in the app can be navigated to with a
URL, regardless of the platform.
Core concepts of file-based routing in Expo Router
• Automatic Entry Point:
o Expo Router does not require explicit code to define the first screen.
Instead, it automatically designates the [Link] file that matches the root
URL (/) as the initial route.
• Route Groups:
o By using parentheses in directory names—such as
app/(tabs)/—developers can organize files into groups that do not appear
in the final URL.
• Defaulting to Tabs:
o If want the app to start on a specific tab, just place an [Link] file inside a
route group.
Core concepts of file-based routing in Expo Router
• Architectural Shift:
o The app/_layout.jsx file effectively replaces the traditional [Link] as the
entry point of the application.
• Mandatory Presence:
o Every Expo Router project should have this file _layout.jsx located directly
within the root of the /app directory.
• Execution Priority:
o This file _layout.jsx is rendered before any other route in the application,
ensuring that global logic is established first.
Core concepts of file-based routing in Expo Router
• Non-navigation components live outside of app directory
o Other parts of your app, like components, hooks, utilities, and so on,
should be placed in other top-level directories.
o If put a non-route inside of the app directory, Expo Router will attempt to
treat it like a route.
• It's still React Navigation under the hood
o Expo Router is actually built on top of React Navigation.
o Refer to React Navigation documentation for how to style or configure
navigation, as the default stack and tab navigators use the exact same
options.
Router Notation
• Simple names/no notation
• Regular file and directory names without any
notation signify static routes
• Their URL matches exactly as they appear in the file
tree
• Square brackets
• A dynamic route
• The name of the route includes a parameter that
can be used when rendering the page. The
parameter could be either in a directory name or a
file name
Router Notation
• Parentheses
• A directory with its name surrounded in
parentheses indicates a route group. These
directories are useful for grouping routes together
without affecting the URL
• Plus sign
• Routes that include a + have special significance to
Expo Router, and are used for specific purposes.
Navigation
• Use the useRouter hook to access navigation functions
• Usage:
import { useRouter } from 'expo-router’;
export default function Home() {
const router = useRouter();
...
}
• Expo Router default to stack navigation
Deep Linking
• Is a URL to open a specific page in the app.
• Especially useful for sharing links to specific pages in your app.
• On web, deep linking is as simple as navigating to that specific
URL in your web browser. On mobile, defining a scheme in app
config file, and this becomes the prefix for deep links into the app.
Common navigation patterns in Expo Router
• Stacks inside tabs: Nested navigators
app/(tabs)/_layout.jsx
Common navigation patterns in Expo Router
• Stacks inside tabs: Nested navigators
app/(tabs)/feed/_layout.jsx
Common navigation patterns in Expo Router
• One screen, two tabs: sharing routes
• Route groups can be used to share a
single screen between two different tabs.
app/(tabs)/_layout.jsx
app/(tabs)/(feed,search)/_layout.jsx
Common navigation patterns in Expo Router
• Authenticated users only: protected
routes
• Have a set of routes that should only be
accessible to authenticated users
Wrap screen in a [Link] with
guard={true} to become inaccessible and
the next available screen will be opened instead
Stack Navigator
• The foundational way of navigating between
routes in an app
• A stacked route animates:
• On top of the current screen (Android)
• From the right of the current screen (iOS)
For example
index route is the first route in the stack
details route is pushed on top of the index
route when navigated
Stack Navigation
• Statically configure route options
• Can configure the header bar
• Optionally configure static a route’s
options
• Also useful for tabs or drawers
Stack Navigation
• [Link]()
• Either push a new page onto the stack or
unwind to an existing route on the stack.
• [Link]();
• Explicitly push a new page onto the stack
• [Link]();
• Go back to the previous page
• [Link]();
• Replace the current page on the stack.
Stack Navigation
• Removing stack screens
• [Link]()
• Dismisses the last screen in the closest stack
• If the current is the only route in the stack, it will dismiss the entire stack
• [Link]()
• Operates similarly to navigation function
• [Link]()
• Return to the first screen in the closest stack
• Similar to popToTop stack action
• [Link]()
• Check if it is possible to dismiss the current screen
Types of Tabs Navigation
• JavaScript Tabs
• Is implemented with React Navigation's bottom tabs
• Native Tabs
• Uses a platform’s native tab bar
• Offer native look and feel
• Custom Tabs
• Provides headless tab components to build a fully custom tab layout
JavaScript Tabs Navigation
JavaScript Tabs Navigation
app/_layout.jsx
import { Stack } from 'expo-router’;
export default function Layout() {
return (
<Stack>
<[Link] name="(tabs)" options={{
headerShown: false }} />
</Stack>
);
}
JavaScript Tabs Navigation
app/(tabs)/_layout.jsx
JavaScript Tabs Navigation
app/(tabs)/[Link] & app/(tabs)/[Link]
Native Tabs Navigation
Native Tabs Navigation
• An alpha version and be available in SDK 55 or later
app/_layout.jsx
Native Tabs Navigation
app/[Link] and app/[Link]
Drawer Navigation
• Allow users to swipe open a menu from a side of the screen to
expose navigation options
• Also typically toggleable through a button in the app header
• Installation
npx expo install @react-navigation/drawer
react-native-reanimated react-native-worklets
Drawer Navigation
app/_layout.jsx
The useContext hook
• A React Hook that lets you create context data (values) in a parent
component and retrieve them from its descendant components.
• The component what retrieves the data can be many levels down in the
component tree.
• How to create and use a context?
• Create a context provider and wrap it around the components where you
want to retrieve values.
• Call useContext function in a descendant component to retrieve the
context value(s).
Creating & using Context Provider
• First, use the createContext function to create a Context.
• The parameter specifies the context’s initial value.
import { createContext, useContext } from 'react';
const ScreenNameContext = createContext(null);
• Then, wrap the context’s provider around the components that
will use the context value.
<[Link] value={scrNames}>
<Stack>
<[Link] name="Home" component={HomeScreen} />
<[Link] name="About" component={AboutScreen} />
</Stack>
</[Link]>
Retrieving Context Data from a component
• Technically, any can retrieve the context data.
• However, it’s recommended that the component is one of the
context provider’s descendant.
function AboutScreen() {
const screenNames = useContext(ScreenNameContext);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{[Link]}</Text>
</View>
);
}
function AboutScreen() {
const screenNames = useContext(ScreenNameContext);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{[Link]}</Text>
</View>
);
}
export default function App() {
const scrNames = {
home: 'Home Screen',
about: 'About screen'
};
return (
<[Link] value={scrNames}>
<Stack>
<[Link] name="Home" component={HomeScreen} />
<[Link] name="About" component={AboutScreen} />
</Stack>
</[Link]>
);
}
Moving between screens
• On a web browser, we'd be able to write something like this:
<a href="[Link]">About Us</a>
• Another way to write this would be:
<button onclick="() => {
[Link] = '[Link]';
}"> About Us</button>
• We can do something similar to the latter, but rather than using
[Link], we'll use the navigation object that's accessible
in the screen components.
Navigating to a new screen
import { useNavigation } from 'expo-router';
function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>Home Page</Text>
<Button
title="About Us"
onPress={() => [Link]('About')}
/>
</View>
);
}
Navigating to a new screen
• navigation − the navigation object is returned
from the useNavigation hook.
• navigate('About') − we call the navigate
function with the name of the route that we'd like to
move the user to.
• Note:
• If we call [Link] with a route name that
we haven't defined in a navigator, it’ll print an error in
development builds and nothing will happen in production
builds (in other words, we can only navigate to routes that
have been defined in the navigator).
The issue of navigating to the same screen
• If you're already on the About screen and call
[Link]('About'), nothing happens.
• The navigate function only navigates to the screen if it's not
already active.
• What if you actually want to navigate to the same screen again
and again?
• For instance, when you want to pass some unique data into a screen.
e.g. you have a ProductDetail screen that will display a product that
is passed into it as a prop.
Using push to add multiple instances
• If you want to open a new instance of the About
screen, use [Link]('About').
• Each time push is called, a new About screen instance
is added to the navigation stack.
<Button
title="About Us... again"
onPress={() => [Link]('About')}
/>
Difference between navigate and push
• navigate('About') → Does nothing if already on the About
screen.
• [Link]('About') → Creates a new instance of the
About screen.
This approach is useful when passing unique data to each
instance of a screen.
Going back
• Automatic Back Button in Header
• The native stack navigator automatically provides a back button if there's
a previous screen in the stack.
• If there's only one screen, the back button won't appear.
• Manually Triggering Back Navigation
• Use [Link]() to programmatically navigate to the
previous screen.
• On Android, React Navigation automatically calls goBack()
when the user presses the physical back button.
Going back
function AboutScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>About Page</Text>
<Button
title="About Us... again"
onPress={() => [Link]('About')}
/>
<Button
title="Go Back"
onPress={() => [Link]()}
/>
</View>
);
}
Going back multiple screens
• Another common requirement is to be able to go
back multiple screens -- for example, if you are
several screens deep in a stack and want to
dismiss all of them to go back to the first screen.
• In this case, we know that we want to go back to
Home so we can use popTo(‘Home’). Another
alternative would be
[Link](), which goes back
to the first screen in the stack.
Going Back Multiple Screens
function AboutScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>About Page</Text>
<Button title="About Us... again"
onPress={() => [Link]('About')} />
<Button title="Go Back" onPress={() => [Link]()} />
<Button title="Go Home" onPress={() => [Link]('Home')} />
<Button title="Back to First Screen in Stack"
onPress={() => [Link]()} />
</View>
);
}
Going Back
• Example use cases:
• goBack() → Go back one screen.
• popTo('Home') → Return directly to the Home screen.
• popToTop() → Reset navigation to the first screen in the stack.