Expo Router у React Native: Повний посібник з файлової навігації
Повний посібник з Expo Router у React Native — файлова навігація, динамічні маршрути, вкладки, модальні екрани та захист маршрутів. Актуальний гайд 2026 року.

Expo Router впроваджує файлову маршрутизацію в React Native, замінюючи ручне налаштування навігації конвенційним підходом, натхненним Next.js. Починаючи з Expo SDK 55 та Expo Router v6, створення кросплатформної навігації для Android, iOS та веб зводиться до розміщення файлів у правильному каталозі.
Нові проєкти Expo постачаються з попередньо налаштованим Expo Router. Достатньо виконати npx create-expo-app@latest --template default@sdk-55, щоб розпочати роботу з файловою навігацією. Для існуючих проєктів необхідно встановити expo-router та оновити точку входу.
Як працює файлова маршрутизація в Expo Router
Кожен файл у каталозі app автоматично стає маршрутом. Шлях до файлу безпосередньо відповідає URL-шляху, усуваючи потребу в централізованому налаштуванні навігації. Файл app/settings.tsx створює маршрут /settings, а app/profile/edit.tsx відповідає маршруту /profile/edit.
Такий підхід пропонує три ключові переваги порівняно з традиційним налаштуванням React Navigation:
- Нульова конфігурація: маршрути з'являються в момент створення файлу
- Автоматичний deep linking: кожен екран отримує URL, що забезпечує можливість поширення та тестування
- Типізована навігація: TypeScript знає, які маршрути існують на етапі компіляції
import { View, Text, StyleSheet } from 'react-native'
import { Link } from 'expo-router'
export default function HomeScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome</Text>
{/* Link maps directly to file path */}
<Link href="/settings" style={styles.link}>
Open Settings
</Link>
<Link href="/profile/edit" style={styles.link}>
Edit Profile
</Link>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', padding: 24 },
title: { fontSize: 28, fontWeight: 'bold', marginBottom: 16 },
link: { fontSize: 16, color: '#61DAFB', marginTop: 12 },
})Компонент Link забезпечує навігацію на всіх платформах. У вебі він рендериться як тег <a> з відповідним атрибутом href для SEO. На нативних платформах він ініціює стекову навігацію.
Структура проєкту та файли макетів
Expo Router використовує файли _layout.tsx для визначення контейнерів навігації. Кожен каталог може мати власний макет, створюючи вкладені ієрархії навігації. Кореневий макет обгортає весь застосунок, тоді як вкладені макети контролюють окремі розділи.
Типова структура проєкту виглядає наступним чином:
app/
_layout.tsx # Root layout (Stack or custom)
index.tsx # Home screen (/)
(tabs)/ # Tab group (parentheses = route group)
_layout.tsx # Tab navigator
home.tsx # /home tab
search.tsx # /search tab
profile.tsx # /profile tab
settings/
_layout.tsx # Settings stack layout
index.tsx # /settings
notifications.tsx # /settings/notifications
privacy.tsx # /settings/privacyГрупи маршрутів — каталоги, загорнуті в дужки — організовують файли без впливу на URL. Каталог (tabs) вище створює навігатор вкладок, але URL-адреси залишаються у вигляді /home, /search та /profile, а не /tabs/home.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack
screenOptions={{
headerStyle: { backgroundColor: '#1a1a2e' },
headerTintColor: '#ffffff',
headerTitleStyle: { fontWeight: '600' },
}}
>
<Stack.Screen name="index" options={{ title: 'Home' }} />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="settings" options={{ title: 'Settings' }} />
</Stack>
)
}Кореневий макет також є місцем для завантаження шрифтів, ініціалізації провайдерів та налаштування глобальних параметрів — замінюючи традиційний файл App.tsx як точку входу.
Створення навігації вкладками з Expo Router
Навігація вкладками потребує файлу _layout.tsx всередині групи маршрутів. Expo Router v6 представляє NativeTabs для платформоспецифічного досвіду вкладок, але стандартний компонент Tabs з Expo Router покриває більшість випадків використання.
import { Tabs } from 'expo-router'
import { Ionicons } from '@expo/vector-icons'
export default function TabLayout() {
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: '#61DAFB',
tabBarInactiveTintColor: '#888',
tabBarStyle: {
backgroundColor: '#1a1a2e',
borderTopColor: '#2d2d44',
},
}}
>
<Tabs.Screen
name="home"
options={{
title: 'Home',
tabBarIcon: ({ color, size }) => (
<Ionicons name="home" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="search"
options={{
title: 'Search',
tabBarIcon: ({ color, size }) => (
<Ionicons name="search" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="profile"
options={{
title: 'Profile',
tabBarIcon: ({ color, size }) => (
<Ionicons name="person" size={size} color={color} />
),
}}
/>
</Tabs>
)
}Кожен файл екрану вкладки експортує стандартний React-компонент. Іконка, мітка та значок панелі вкладок налаштовуються через властивість options у макеті.
Динамічні маршрути та параметри маршрутів
Динамічні сегменти використовують квадратні дужки в назві файлу. Файл із назвою [id].tsx відповідає будь-якому окремому сегменту, тоді як [...slug].tsx перехоплює всі наступні сегменти.
import { View, Text, StyleSheet } from 'react-native'
import { useLocalSearchParams, Stack } from 'expo-router'
export default function ProductScreen() {
// Extract the dynamic parameter from the URL
const { id } = useLocalSearchParams<{ id: string }>()
return (
<View style={styles.container}>
<Stack.Screen options={{ title: `Product ${id}` }} />
<Text style={styles.heading}>Product Details</Text>
<Text style={styles.id}>ID: {id}</Text>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 24 },
heading: { fontSize: 24, fontWeight: 'bold', marginBottom: 8 },
id: { fontSize: 16, color: '#888' },
})При переході до /product/42 цей екран рендериться з параметром id, встановленим у "42". Хук useLocalSearchParams забезпечує типізований доступ до всіх параметрів маршруту.
Для маршрутів типу catch-all файл [...slug].tsx перехоплює цілі сегменти шляху:
import { useLocalSearchParams } from 'expo-router'
export default function DocsScreen() {
// /docs/getting-started/installation → slug = ['getting-started', 'installation']
const { slug } = useLocalSearchParams<{ slug: string[] }>()
return <DocViewer path={slug.join('/')} />
}Готовий до співбесід з React Native?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Типізовані маршрути для безпеки на етапі компіляції
Expo Router автоматично генерує типи маршрутів при увімкненій опції typed routes. Це дозволяє виявляти некоректні посилання на етапі компіляції, а не під час виконання.
Активація типізованих маршрутів у файлі app.json:
{
"expo": {
"experiments": {
"typedRoutes": true
}
}
}Після активації властивість href компонента Link та аргумент router.push() приймають лише валідні рядки маршрутів:
import { router } from 'expo-router'
function handleCheckout(cartId: string) {
// TypeScript validates this route exists
router.push(`/product/${cartId}`)
// This would cause a compile error if /nonexistent doesn't exist
// router.push('/nonexistent')
}Типізовані маршрути ідеально поєднуються з useLocalSearchParams. Згенеровані типи гарантують відповідність імен параметрів між визначенням маршруту та компонентом, що його використовує, запобігаючи неочевидним помилкам, які проявляються лише при переході на конкретний екран.
Модальні екрани та параметри презентації
Модальні вікна в Expo Router — це звичайні екрани, налаштовані з параметром presentation: 'modal' у макеті. Такий підхід зберігає файлову конвенцію — модальне вікно є просто ще одним маршрутом.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
{/* Modal screen slides up from the bottom */}
<Stack.Screen
name="create-post"
options={{
presentation: 'modal',
headerTitle: 'New Post',
}}
/>
</Stack>
)
}import { View, TextInput, Button, StyleSheet } from 'react-native'
import { router } from 'expo-router'
import { useState } from 'react'
export default function CreatePostModal() {
const [title, setTitle] = useState('')
const handleSubmit = () => {
// Submit logic here
router.back() // Dismiss the modal
}
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Post title"
value={title}
onChangeText={setTitle}
/>
<Button title="Publish" onPress={handleSubmit} />
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 24 },
input: {
borderWidth: 1,
borderColor: '#333',
borderRadius: 8,
padding: 12,
fontSize: 16,
marginBottom: 16,
},
})При переході до /create-post активується модальна презентація. Виклик router.back() закриває модальне вікно, повертаючись до попереднього екрану в стеку.
Програмна навігація та API маршрутизатора
Окрім компонента Link, Expo Router надає імперативний API через об'єкт router. Він обробляє навігацію, ініційовану бізнес-логікою, а не безпосередньою взаємодією користувача.
import { router } from 'expo-router'
// Push a new screen onto the stack
router.push('/profile/settings')
// Replace the current screen (no back button)
router.replace('/login')
// Go back to the previous screen
router.back()
// Navigate with parameters
router.push({
pathname: '/product/[id]',
params: { id: '42', source: 'recommendations' },
})
// Check if going back is possible
import { useRouter } from 'expo-router'
function BackButton() {
const router = useRouter()
return router.canGoBack() ? (
<Button title="Back" onPress={() => router.back()} />
) : null
}Різниця між router.push та router.replace має значення при потоках автентифікації. Після успішного входу router.replace('/dashboard') запобігає поверненню до екрану входу.
router.replace() замінює поточний запис в історії навігації. Для механізмів захисту, що перенаправляють неавтентифікованих користувачів, слід використовувати <Redirect href="/login" /> всередині рендеру компонента — він спрацьовує на етапі рендерингу та коректно працює з серверним рендерингом.
Middleware та захист маршрутів
Expo Router v6 впроваджує серверне middleware для логіки на рівні маршрутів. Файл +middleware.ts перехоплює запити до їх потрапляння до компонента маршруту, забезпечуючи перевірку автентифікації, перенаправлення та маніпуляцію заголовками.
import { type MiddlewareRequest } from 'expo-router/server'
export function middleware(request: MiddlewareRequest) {
const { pathname } = request.nextUrl
// Protect dashboard routes
const protectedPaths = ['/dashboard', '/settings', '/profile']
const isProtected = protectedPaths.some(p => pathname.startsWith(p))
if (isProtected) {
const token = request.cookies.get('session')
if (!token) {
return Response.redirect(new URL('/login', request.url))
}
}
return undefined // Continue to route
}На нативних платформах, де серверне middleware не працює, захист маршрутів спирається на клієнтські механізми. Поширений патерн полягає в обгортанні захищених макетів перевіркою автентифікації:
import { Redirect, Stack } from 'expo-router'
import { useAuth } from '@/hooks/useAuth'
export default function AuthenticatedLayout() {
const { isLoggedIn, isLoading } = useAuth()
if (isLoading) return null
if (!isLoggedIn) return <Redirect href="/login" />
return <Stack />
}Серверне middleware працює виключно у вебі з серверним рендерингом. Для нативних застосунків завжди слід реалізовувати клієнтський захист маршрутів у компонентах макетів. Поєднання обох підходів гарантує послідовний захист на всіх платформах.
Висновок
- Expo Router v6 замінює ручне налаштування навігації файловими конвенціями, автоматично перетворюючи кожен файл у каталозі
appна маршрут - Макети, визначені через файли
_layout.tsx, створюють ієрархії навігації — стеки, вкладки та бічні панелі — без централізованої конфігурації - Динамічні маршрути з
[param].tsxта маршрути catch-all з[...slug].tsxзабезпечують параметризовану навігацію з повною підтримкою TypeScript - Типізовані маршрути виявляють некоректні навігаційні посилання на етапі компіляції після увімкнення в
app.json - Модальні екрани, програмна навігація через
router.push/replace/backта серверне middleware доповнюють інструментарій маршрутизації - Групи маршрутів із каталогами в дужках організовують код без впливу на URL-адреси, зберігаючи чисту структуру файлів при зростанні застосунку
- Клієнтський захист маршрутів у макетах забезпечує автентифікацію на нативних платформах, а серверне middleware покриває веб — обидва підходи разом створюють надійний захист для кросплатформних застосунків
Теги
Поділитися
