Linking
Use the <Link />
component to navigate between pages. This is conceptually similar to the <a>
element in HTML.
import { Link } from "expo-router";
export default function Page() {
return (
<View>
<Link href="/">Home</Link>
</View>
);
}
href
accepts relative paths like../settings
or full paths like/profile/settings
. Relative paths are useful for shared routes.href
can also accept an object like{ pathname: 'profile', params: { id: '123' } }
to navigate to dynamic routes.- Use the
replace
prop to replace the current route in the history instead of pushing a new route.
The Link component renders a <Text>
component by default. You can customize the component by passing asChild
which will forward all props to the first child of the Link component. The child component must support the onPress
and onClick
props, href
and accessibilityRole
will also be passed down.
import { Pressable, Text } from "react-native";
import { Link } from "expo-router";
function Home() {
return (
<Link href="/other" asChild>
<Pressable>{({ hovered, pressed }) => <Text>Home</Text>}</Pressable>
</Link>
);
}
useRouter
For more advanced use cases, you can use the imperative useRouter()
hook to navigate imperatively.
import { View, Text } from "react-native";
import { useRouter } from "expo-router";
export default function Page() {
const router = useRouter();
return (
<View>
<Text
onPress={() => {
router.push("/profile/settings");
}}
>
Settings
</Text>
</View>
);
}
- push:
(href: Href) => void
Navigate to a route. You can provide a full path like/profile/settings
or a relative path like../settings
. Navigate to dynamic routes by passing an object like{ pathname: 'profile', params: { id: '123' } }
. - replace:
(href: Href) => void
Same API aspush
but replaces the current route in the history instead of pushing a new one. This is useful for redirects. - back:
() => void
Navigate back to previous route. - setParams:
(params: Record<string, string>) => void
Update the query params for the currently selected route.
Href
type
The Href
type is a union of the following types:
- string: A full path like
/profile/settings
or a relative path like../settings
. - object: An object with a
pathname
and optionalparams
object. Thepathname
can be a full path like/profile/settings
or a relative path like../settings
. Theparams
can be an object of key/value pairs.
usePathname
Returns the currently selected route location without search parameters. e.g. /acme?foo=bar
-> /acme
. Segments will be normalized: /[id]?id=normal
-> /normal
/profile/baconbrix?extra=info
import { Text } from "react-native";
import { usePathname } from "expo-router";
export default function Route() {
const pathname = usePathname();
// pathname = "/profile/baconbrix"
return <Text>User: {user}</Text>;
}
useLocalSearchParams
Returns the URL search parameters for the contextually selected route. e.g. /acme?foo=bar
-> { foo: "bar" }
. This is useful for stacks where the previous screen is still mounted.
app/
_layout.js
[first]/home.tsx
[second]/shop.tsx
When /abc/home
pushes /123/shop
, useGlobalSearchParams
would return { first: undefined, second: '123' }
on /app/[first]/home.tsx
because the global URL has changed. However, you may want the params to remain { first: 'abc' }
to reflect the context of the screen. In this case, you can use useLocalSearchParams
to ensure the params { first: 'abc' }
are still returned in /app/[first]/home.tsx
.
/profile/baconbrix?extra=info
import { Text } from "react-native";
import { useLocalSearchParams } from "expo-router";
export default function Route() {
const { user, extra } = useLocalSearchParams();
return <Text>User: {user}</Text>;
}
This function can be typed using an abstract:
import { useLocalSearchParams } from "expo-router";
export default function Route() {
const { user, extra } = useLocalSearchParams<{
user: string;
extra?: string;
}>();
}
useGlobalSearchParams
Returns the URL search parameters for the globally selected route. e.g. /acme?foo=bar
-> { foo: "bar" }
.
/profile/baconbrix?extra=info
import { Text } from "react-native";
import { useGlobalSearchParams } from "expo-router";
export default function Route() {
const { user, extra } = useGlobalSearchParams();
return <Text>User: {user}</Text>;
}
Given a route at app/profile/[id].tsx
if the hook is called while the URL is /profile/123
, the results of useGlobalSearchParams
would be as follows:
{
id: "123";
}
This function can be typed using an abstract:
import { useGlobalSearchParams } from "expo-router";
export default function Route() {
const { user, extra } = useGlobalSearchParams<{
user: string;
extra?: string;
}>();
}
useSegments
Returns a list of segments for the currently selected route. Segments are not normalized, so they will be the same as the file path. e.g. /[id]?id=normal
-> ["[id]"]
import { Text } from "react-native";
import { useSegments } from "expo-router";
export default function Route() {
const segments = useSegments();
// segments = ["profile", "[user]"]
return <Text>Hello</Text>;
}
This function can be typed using an abstract of string arrays:
import { useSegments } from "expo-router";
export default function Route() {
const segments = useSegments<["profile"] | ["profile", "[user]"]>();
}
useNavigation
Access the underlying React Navigation navigation
prop to imperatively access layout-specific functionality like navigation.openDrawer()
in a Drawer layout. Learn more.
import { useNavigation } from "expo-router";
export default function Route() {
const navigation = useNavigation();
return (
<View>
<Text
onPress={() => {
navigation.openDrawer();
}}
>
Open Drawer
</Text>
</View>
);
}
useSearchParams
This function has been renamed to useGlobalSearchParams
. Often, you'll want to use useLocalSearchParams
unless you're attempting to observe and report the global state.
Redirect
You can immediately redirect from a particular screen by using the Redirect
component:
import { View, Text } from "react-native";
import { Redirect } from "expo-router";
export default function Page() {
// Some logic to determine if the user is logged in.
const { user } = useAuth();
if (!user) {
// Redirect to the login screen if the user is not authenticated.
return <Redirect href="/login" />;
}
return (
<View>
<Text>Welcome Back!</Text>
</View>
);
}
You can also redirect imperatively using the useRouter
hook:
import { Text } from "react-native";
import { useRouter, useFocusEffect } from "expo-router";
function MyScreen() {
const router = useRouter();
useFocusEffect(() => {
// Call the replace method to redirect to a new route without adding to the history.
// We do this in a useFocusEffect to ensure the redirect happens every time the screen
// is focused.
router.replace("/profile/settings");
});
return <Text>My Screen</Text>;
}
Testing
On native, you can use the uri-scheme
CLI to test opening native links on a device.
For example, if you want to launch the Expo Go app on iOS to the /form-sheet
route, you can run:
Replace
192.168.87.39:19000
with the IP address shown when runningnpx expo start
.
npx uri-scheme open exp://192.168.87.39:19000/--/form-sheet --ios
You can also search for links directly in a browser like Safari or Chrome to test deep linking on physical devices. Learn more about testing deep links.
Sitemap
We currently inject a /_sitemap
file which provides a list of all routes in the app. This is useful for debugging and development. This screen is only injected during development, and won't be available in production.
We may remove this feature for the official release, but it's useful for now.