Expo Router di React Native: Panduan Lengkap Navigasi Berbasis File
Panduan lengkap Expo Router untuk React Native mencakup routing berbasis file, layout, rute dinamis, navigasi bertipe, dan pola lanjutan seperti modal dan tab.

Expo Router menghadirkan routing berbasis file ke React Native, menggantikan konfigurasi navigasi manual dengan pendekatan berbasis konvensi yang terinspirasi dari Next.js. Sejak Expo SDK 57 dan Expo Router, pengembangan navigasi lintas platform untuk Android, iOS, dan web hanya memerlukan pembuatan file di direktori yang tepat.
Proyek Expo baru sudah menyertakan Expo Router secara default. Perintah npx create-expo-app@latest --template default menghasilkan proyek yang telah dikonfigurasi dengan routing berbasis file. Untuk proyek yang sudah ada, cukup instal package expo-router dan perbarui entry point aplikasi.
Cara Kerja Routing Berbasis File di Expo Router
Setiap file yang ditempatkan di dalam direktori app secara otomatis menjadi sebuah rute. Jalur file berkorespondensi langsung dengan jalur URL, sehingga menghilangkan kebutuhan akan file konfigurasi terpusat. File app/settings.tsx menciptakan rute /settings, sedangkan app/profile/edit.tsx berkorespondensi dengan /profile/edit.
Pendekatan ini menawarkan tiga keunggulan utama dibandingkan konfigurasi tradisional menggunakan React Navigation:
- Tanpa konfigurasi: rute terbentuk secara otomatis begitu file dibuat
- Deep linking otomatis: setiap layar memiliki URL tersendiri, memudahkan proses berbagi dan pengujian
- Navigasi bertipe: TypeScript mengenali rute yang tersedia sejak tahap kompilasi
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 },
})Komponen Link menangani navigasi di semua platform. Di web, komponen ini menghasilkan elemen anchor dengan atribut href yang sesuai untuk keperluan SEO. Di platform native, komponen ini memicu navigasi bertipe stack.
Struktur Proyek dan File Layout
Expo Router menggunakan file _layout.tsx untuk mendefinisikan kontainer navigasi. Setiap direktori dapat memiliki layout-nya sendiri, sehingga memungkinkan terciptanya hierarki navigasi bersarang. Layout root membungkus keseluruhan aplikasi, sementara layout bersarang mengontrol bagian-bagian tertentu.
Berikut adalah struktur proyek yang umum digunakan:
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/privacyGrup rute, yaitu direktori yang diapit tanda kurung, berfungsi untuk mengelompokkan file tanpa memengaruhi URL. Direktori (tabs) di atas membentuk navigator tab, namun URL tetap menjadi /home, /search, dan /profile, bukan /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>
)
}Layout root juga berperan sebagai titik inisialisasi untuk pemuatan font, pengaturan provider, dan konfigurasi global lainnya.
Membangun Navigasi Tab dengan Expo Router
Navigasi tab memerlukan file _layout.tsx di dalam sebuah grup rute. Expo Router menyediakan NativeTabs untuk pengalaman tab spesifik platform dan komponen standar Tabs untuk sebagian besar kebutuhan. Sejak SDK 56, Native Tabs mendukung properti disabled untuk mencegah pemilihan tab sambil tetap menampilkannya.
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>
)
}Setiap file layar tab mengekspor komponen React standar. Ikon, label, dan badge pada tab bar dikonfigurasi melalui prop options di layout.
Rute Dinamis dan Parameter Rute
Segmen dinamis menggunakan tanda kurung siku pada nama file. File bernama [id].tsx mencocokkan satu segmen, sedangkan [...slug].tsx menangkap seluruh segmen yang tersisa pada jalur URL.
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' },
})Mengakses /product/42 akan menampilkan layar ini dengan variabel id bernilai "42". Hook useLocalSearchParams menyediakan akses bertipe terhadap seluruh parameter rute.
Untuk rute catch-all, [...slug].tsx menangkap segmen jalur secara keseluruhan:
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('/')} />
}Siap menguasai wawancara React Native Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Typed Routes: Keamanan pada Tahap Kompilasi
Expo Router secara otomatis menghasilkan tipe rute ketika fitur typed routes diaktifkan. Pemeriksaan ini mendeteksi tautan yang rusak pada tahap kompilasi, bukan saat aplikasi dijalankan.
Aktivasi dilakukan melalui file app.json:
{
"expo": {
"experiments": {
"typedRoutes": true
}
}
}Setelah diaktifkan, prop href pada komponen Link dan argumen pada router.push() hanya menerima string yang sesuai dengan rute yang valid:
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')
}Fitur typed routes bekerja sangat baik dengan useLocalSearchParams. Tipe yang dihasilkan menjamin kecocokan antara nama parameter pada definisi rute dan parameter yang digunakan oleh komponen pemanggil, sehingga mencegah bug halus yang baru muncul saat navigasi ke layar tertentu.
Layar Modal dan Opsi Presentasi
Modal di Expo Router merupakan layar biasa yang dikonfigurasi dengan presentation: 'modal' pada layout. Pendekatan ini tetap menghormati konvensi routing berbasis file: modal pada dasarnya hanyalah sebuah rute seperti rute lainnya.
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,
},
})Mengakses /create-post akan memicu presentasi modal. Pemanggilan router.back() menutup modal dan mengembalikan pengguna ke layar sebelumnya dalam tumpukan navigasi.
Navigasi Programatik dan API Router
Selain komponen Link, Expo Router menyediakan API imperatif melalui objek router. API ini memungkinkan pengelolaan navigasi yang dipicu oleh logika bisnis, bukan hanya oleh interaksi langsung pengguna.
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
}Perbedaan antara router.push dan router.replace sangat krusial dalam alur autentikasi di React Native. Setelah login berhasil, router.replace('/dashboard') mencegah pengguna kembali ke layar login melalui tombol kembali.
router.replace() menggantikan entri saat ini dalam riwayat navigasi. Untuk guard autentikasi yang mengalihkan pengguna yang belum login, disarankan menggunakan <Redirect href="/login" /> di dalam render komponen. Pendekatan ini bekerja pada fase render dan berfungsi dengan baik bersama server-side rendering di web.
Middleware dan Proteksi Rute
Expo Router menyediakan middleware server untuk logika pada level rute. File +middleware.ts mencegat permintaan sebelum mencapai komponen rute, memungkinkan pemeriksaan autentikasi, pengalihan, dan manipulasi header HTTP.
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
}Pada platform native, middleware server tidak dijalankan. Proteksi rute mengandalkan guard di sisi klien. Pola yang paling umum digunakan adalah membungkus layout yang dilindungi dengan pemeriksaan autentikasi:
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 server hanya berjalan di web dengan server-side rendering. Untuk aplikasi native, implementasi guard di sisi klien pada komponen layout bersifat wajib. Mengombinasikan kedua pendekatan ini menjamin proteksi yang konsisten di seluruh platform.
Migrasi SDK 56: Fork React Navigation
Sejak Expo SDK 56, Expo Router tidak lagi bergantung pada package @react-navigation/*. Jika proyek mengimpor langsung dari React Navigation, perbarui import tersebut:
| Package Asli | Lokasi Baru |
|---|---|
@react-navigation/native | expo-router/react-navigation |
@react-navigation/stack | expo-router/js-stack |
@react-navigation/bottom-tabs | expo-router/js-tabs |
Jalankan codemod untuk memperbarui import secara otomatis:
npx expo-codemod sdk-56-expo-router-react-navigation-replace srcAPI runtime tetap sama. Hanya module specifier yang berpindah. Library pihak ketiga yang masih mengimpor dari @react-navigation/core tetap berfungsi karena Expo CLI menulis ulang import tersebut saat bundling.
Sumber Referensi
- Dokumentasi Expo Router - panduan resmi dan referensi API
- Changelog Expo SDK 57 - catatan rilis stabil terkini
- Blog Post Expo Router v56 - penjelasan fork React Navigation
- Panduan Migrasi SDK 55 ke 56 - langkah migrasi import
Yang Perlu Diketahui untuk Wawancara tentang Expo Router
- Expo Router memetakan setiap file dalam direktori
appke sebuah rute secara otomatis, menghilangkan konfigurasi navigasi manual - Layout yang didefinisikan melalui file
_layout.tsxmembentuk hierarki navigasi untuk stack, tab, dan drawer - Rute dinamis dengan
[param].tsxdan rute catch-all dengan[...slug].tsxmenangani navigasi berparameter dengan dukungan TypeScript penuh - Typed routes mendeteksi tautan navigasi yang rusak pada tahap kompilasi saat diaktifkan di
app.json - Layar modal, navigasi programatik melalui
router.push/replace/back, dan middleware server melengkapi perangkat routing - Grup rute menggunakan direktori bertanda kurung mengelompokkan kode tanpa memengaruhi URL
- Guard di sisi klien pada layout menangani autentikasi di platform native, sementara middleware server mencakup web
- Sejak SDK 56, import dari
@react-navigation/*harus diperbarui ke padananexpo-router/*
Untuk materi lebih lanjut tentang arsitektur React Native dan persiapan wawancara, lihat modul native modules.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Bisakah kamu menemukan bug di React Native?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 6 Oktober 2026
Tag
Bagikan
Artikel terkait

Panduan Pengembangan Aplikasi React Native 2026: Membangun Aplikasi Produksi dan Pertanyaan Interview
Panduan lengkap pengembangan aplikasi React Native 2026 mencakup New Architecture, Expo SDK 56, Hermes V1, dan pertanyaan interview untuk developer React Native.

Pengembangan Aplikasi React Native 2026: Panduan Lengkap dan Pertanyaan Interview
Panduan komprehensif pengembangan aplikasi React Native di tahun 2026. Pelajari New Architecture, JSI, Fabric, TurboModules, dan pertanyaan interview yang sering ditanyakan.

Hermes V1 di React Native 0.84: Performa, Bytecode Precompiled, dan Pertanyaan Interview
Panduan mendalam tentang engine JavaScript Hermes V1 di React Native 0.84, mencakup kompilasi bytecode, garbage collector Hades, optimisasi memori, dan pertanyaan interview teknis.