{"id":"l-rn-3-1","courseId":"react-native-apps","lang":"en","kind":"lesson","summary":"Turn files in src/app into Trailhead’s screens with Expo Router, wrap them in a native stack with a layout file, and move between them with Link and the router object.","html":"<p>On the web, a URL bar shows where you are, and the back button walks through history. On a phone, users see neither: they see screens sliding in from the right, a back arrow or swipe, and tabs at the bottom. Underneath, Expo Router still gives every screen a URL, which is what makes deep links, typed navigation and a web version possible. You get both models at once.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Files are routes</h2>\n<p>Expo Router builds your navigation from the files in <code dir=\"ltr\">src/app</code>. The path of the file is the route:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Text</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code>src/app/\n  _layout.tsx          wraps everything below in a navigator\n  index.tsx            /\n  about.tsx            /about\n  settings/\n    _layout.tsx        wraps the settings screens\n    index.tsx          /settings\n    units.tsx          /settings/units\n  +not-found.tsx       any URL that doesn't match</code></pre></div>\n<p>Each route file default-exports a component. That’s all a screen is:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"tsx\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">src/app/about.tsx</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { Text, View } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'react-native'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> About</span><span style=\"color:#953800;--shiki-dark:#FFA657\">() </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ flex: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, padding: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">16</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Trailhead keeps a private log of your hikes.&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Because <strong>every</strong> file in the folder becomes a route, keep everything else elsewhere: <code dir=\"ltr\">src/components</code>, <code dir=\"ltr\">src/lib</code>, <code dir=\"ltr\">src/state</code>. A row component accidentally saved in <code dir=\"ltr\">src/app</code> becomes a screen that anyone can deep-link to.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Layouts wrap their siblings</h2>\n<p>A <code dir=\"ltr\">_layout.tsx</code> file renders a navigator around the routes in its folder. Trailhead’s root layout uses a <strong>Stack</strong>, the native push-and-pop navigator with platform animations, swipe-back on iOS and the system back gesture on Android:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"tsx\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">src/app/_layout.tsx</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { Stack } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'expo-router'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> RootLayout</span><span style=\"color:#953800;--shiki-dark:#FFA657\">() </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Stack</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> screenOptions</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ headerTintColor: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'#2f6f4e'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Stack.Screen</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"index\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> options</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ title: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Trailhead'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Stack.Screen</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"about\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> options</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ title: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'About'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Stack</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p><code dir=\"ltr\">screenOptions</code> applies to every screen in the stack; each <code dir=\"ltr\">Stack.Screen</code> customizes one, matched by its route <code dir=\"ltr\">name</code>. You don’t have to list every route: unlisted ones still work with default options.</p>\n<p>A few header options cover most needs: <code dir=\"ltr\">title</code>, <code dir=\"ltr\">headerShown: false</code> for screens that draw their own top bar (like the full-screen map from the last lesson), <code dir=\"ltr\">headerBackTitle</code> for the label next to the iOS back arrow, and <code dir=\"ltr\">headerRight</code> for a button such as “Edit”. On iOS, <code dir=\"ltr\">headerLargeTitle: true</code> gives you the big collapsing title from Apple’s own apps, which suits a top-level list like the hike log.</p>\n<p>When a title depends on data (the hike’s name, say), render <code dir=\"ltr\">&lt;Stack.Screen options={{ title: hike.name }} /&gt;</code> inside the screen itself. It renders nothing visible; it configures the header of the screen it’s in.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 250\" role=\"img\" aria-labelledby=\"l-rn-3-1-t1\"><defs><marker id=\"arrow-l-rn-3-1-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-rn-3-1-t1\">The files index.tsx, settings/index.tsx and settings/units.tsx map to the URLs /, /settings and /settings/units; navigating pushes each onto a stack, and back pops the top one.</title>\n  <rect class=\"d-box\" x=\"20\" y=\"30\" width=\"220\" height=\"190\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"40\" y=\"58\">src/app/</text>\n  <text class=\"d-code\" x=\"50\" y=\"92\">index.tsx</text>\n  <text class=\"d-code\" x=\"50\" y=\"132\">settings/index.tsx</text>\n  <text class=\"d-code\" x=\"50\" y=\"172\">settings/units.tsx</text>\n  <path class=\"d-arrow\" d=\"M240 88 L300 88\" marker-end=\"url(#arrow-l-rn-3-1-1)\"/>\n  <path class=\"d-arrow\" d=\"M240 128 L300 128\" marker-end=\"url(#arrow-l-rn-3-1-1)\"/>\n  <path class=\"d-arrow\" d=\"M240 168 L300 168\" marker-end=\"url(#arrow-l-rn-3-1-1)\"/>\n  <text class=\"d-code\" x=\"310\" y=\"92\">/</text>\n  <text class=\"d-code\" x=\"310\" y=\"132\">/settings</text>\n  <text class=\"d-code\" x=\"310\" y=\"172\">/settings/units</text>\n  <rect class=\"d-box-primary\" x=\"480\" y=\"150\" width=\"170\" height=\"40\" rx=\"8\"/>\n  <text class=\"d-label\" x=\"565\" y=\"175\" text-anchor=\"middle\">/</text>\n  <rect class=\"d-box-primary\" x=\"480\" y=\"104\" width=\"170\" height=\"40\" rx=\"8\"/>\n  <text class=\"d-label\" x=\"565\" y=\"129\" text-anchor=\"middle\">/settings</text>\n  <rect class=\"d-box-accent\" x=\"480\" y=\"58\" width=\"170\" height=\"40\" rx=\"8\"/>\n  <text class=\"d-label-strong\" x=\"565\" y=\"83\" text-anchor=\"middle\">/settings/units</text>\n  <text class=\"d-label-muted\" x=\"565\" y=\"40\" text-anchor=\"middle\">Stack (top is visible)</text>\n  <text class=\"d-label-muted\" x=\"565\" y=\"215\" text-anchor=\"middle\">push adds · back pops</text>\n</svg><figcaption>Files become routes, and the layout’s Stack holds the visited screens</figcaption></figure>\n<h2 id=\"sec-3\" tabindex=\"-1\">Moving between screens</h2>\n<p>For anything the user taps, use <code dir=\"ltr\">Link</code>. It renders text by default; with <code dir=\"ltr\">asChild</code> it hands navigation to your own pressable component:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"tsx\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">src/app/index.tsx</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { Link } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'expo-router'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { Pressable, Text, View } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'react-native'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> HikeLog</span><span style=\"color:#953800;--shiki-dark:#FFA657\">() </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ flex: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, padding: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">16</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, gap: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Link</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> href</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"/about\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>About Trailhead&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Link</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Link</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> href</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"/settings\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> asChild</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Pressable</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> accessibilityRole</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"button\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">          &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Settings&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Pressable</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Link</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>From code, after a save or a login, use the <code dir=\"ltr\">router</code> object:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"tsx\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">TSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { router } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'expo-router'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">router.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">push</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'/settings/units'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">); </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// add a screen on top</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">router.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">back</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">();                  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// pop the top screen</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">router.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">replace</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'/'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);            </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// swap the current screen; no way back to it</span></span></code></pre></div>\n<p><code dir=\"ltr\">push</code> is the normal forward move. <code dir=\"ltr\">replace</code> is for flows where returning makes no sense: after onboarding, after logging in, after a “saved!” confirmation. <code dir=\"ltr\">back</code> is what the header’s back arrow and the swipe gesture already do; call it yourself after a form saves so the user lands where they came from. There’s also <code dir=\"ltr\">router.navigate</code>, which goes to a route and, if that route is already in the stack, returns to it instead of pushing a duplicate.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Pushing in a loop</span></p>\n<p>A “Done” button that calls <code dir=\"ltr\">router.push('/')</code> after editing a hike stacks a second copy of the log on top of the first. Do it a few times and the back gesture walks through five identical lists. After finishing a task, go <strong>back</strong> (or <code dir=\"ltr\">replace</code>), don’t push forward to where you came from.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">A stack is not browser history</h2>\n<p>It’s tempting to treat the stack like browser history, but there’s one difference that matters: <strong>every screen in the stack stays mounted</strong>. When you push the hike detail screen, the log underneath keeps its state and scroll position, and its effects keep running. That’s why going back is instant, and also why a screen’s <code dir=\"ltr\">useEffect</code> doesn’t re-run when you return to it. When you need to refresh data every time a screen comes back into view, Expo Router provides <code dir=\"ltr\">useFocusEffect</code>, which runs when the screen gains focus and cleans up when it loses it.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">Not-found and why URLs still matter</h2>\n<p><code dir=\"ltr\">+not-found.tsx</code> renders for any URL that doesn’t match a route, which on mobile happens mostly through deep links from old emails or a renamed screen. Give it a friendly message and a <code dir=\"ltr\">Link</code> home.</p>\n<p>Thinking in URLs pays off later in this section: a notification can open <code dir=\"ltr\">/hikes/42</code> directly, a link in a message can open the app on the right screen, and the same routes run on the web if you ever build Trailhead for it.</p>\n<p>Next you’ll add tabs at the bottom of the app, a detail screen for each hike, and pass the hike’s id through the URL.</p>\n","toc":[{"id":"sec-1","text":"Files are routes","level":2},{"id":"sec-2","text":"Layouts wrap their siblings","level":2},{"id":"sec-3","text":"Moving between screens","level":2},{"id":"sec-4","text":"A stack is not browser history","level":2},{"id":"sec-5","text":"Not-found and why URLs still matter","level":2}],"takeaways":["Every file in <code dir=\"ltr\">src/app</code> is a route, and its path is the URL; keep components, hooks and utilities outside that folder.","A <code dir=\"ltr\">_layout.tsx</code> file wraps its sibling routes in a navigator, such as a native <code dir=\"ltr\">Stack</code>.","Use <code dir=\"ltr\">&lt;Link href&gt;</code> for navigation the user taps, and <code dir=\"ltr\">router.push</code>, <code dir=\"ltr\">router.replace</code> and <code dir=\"ltr\">router.back</code> from code.","<code dir=\"ltr\">push</code> adds a screen to the stack, <code dir=\"ltr\">back</code> pops it, and <code dir=\"ltr\">replace</code> swaps the current screen so the user can’t go back to it."],"further":[{"title":"Expo Router introduction","url":"https://docs.expo.dev/router/introduction/"},{"title":"Core concepts of file-based routing","url":"https://docs.expo.dev/router/basics/core-concepts/"},{"title":"Navigating between pages","url":"https://docs.expo.dev/router/basics/navigation/"}],"quiz":[{"q":"<p>You add <code dir=\"ltr\">src/app/HikeRow.tsx</code> to hold a reusable list row component. What happens?</p>","options":[{"text":"Nothing special; Expo Router only treats files with <code dir=\"ltr\">Screen</code> in the name as routes.","why":"There’s no naming rule like that. Every file in the app directory is a route."},{"text":"Expo Router registers it as a route at <code dir=\"ltr\">/HikeRow</code>, so a component meant for reuse becomes a navigable screen.","why":"Correct. Put shared components in <code dir=\"ltr\">src/components</code> (or anywhere outside <code dir=\"ltr\">src/app</code>)."},{"text":"The build fails, because route files must be lower-case.","why":"Case doesn’t make a file a non-route. It still registers, at <code dir=\"ltr\">/HikeRow</code>."}],"answer":1},{"q":"<p>After a user finishes onboarding, Trailhead navigates to the hike log. Pressing back should not return to onboarding. Which call fits?</p>","options":[{"text":"<code dir=\"ltr\">router.push('/')</code>","why":"<code dir=\"ltr\">push</code> leaves onboarding underneath, so back returns to it."},{"text":"<code dir=\"ltr\">router.back()</code>","why":"That goes to whatever was before onboarding, which isn’t the hike log."},{"text":"<code dir=\"ltr\">router.replace('/')</code>","why":"Correct. <code dir=\"ltr\">replace</code> swaps the current screen for the new one, so there’s nothing to go back to."}],"answer":2},{"q":"<p>Where does a header title for the <code dir=\"ltr\">/settings</code> screen belong?</p>","options":[{"text":"In the layout, <code dir=\"ltr\">&lt;Stack.Screen name=&quot;settings&quot; options={{ title: 'Settings' }} /&gt;</code>, or set from the screen itself with the same component.","why":"Correct. Options can live in the layout (good for static titles) or be rendered inside the screen (good when they depend on data)."},{"text":"In <code dir=\"ltr\">app.json</code> under <code dir=\"ltr\">expo.routes.settings.title</code>.","why":"There’s no such key. Navigation options live in your layouts and screens."},{"text":"In a <code dir=\"ltr\">&lt;title&gt;</code> element at the top of the screen’s JSX.","why":"That’s HTML. Native headers are configured through navigator options."}],"answer":0}],"exercise":{"kind":"fill","language":"text","template":"# URL                       file that renders it\n/                           src/app/{{0}}.tsx\n/settings                   src/app/settings/{{1}}.tsx\n/settings/units             src/app/settings/{{2}}.tsx\n(Stack around settings/*)   src/app/settings/{{3}}.tsx\n(any unknown URL)           src/app/{{4}}.tsx\n\n# In code, after the units form saves, return to /settings:\nrouter.{{5}}();","blanks":[{"answers":["index"]},{"answers":["index"]},{"answers":["units"]},{"answers":["_layout"]},{"answers":["+not-found"]},{"answers":["back","dismiss"]}],"title":"Map Trailhead's URLs to files","prompt":"<p>Fill in the file names (without <code dir=\"ltr\">.tsx</code>) so Expo Router renders each URL from the right file, wraps the settings screens in their own layout, and shows a friendly screen for unknown URLs. Then pick the <code dir=\"ltr\">router</code> method that returns from <code dir=\"ltr\">/settings/units</code> to <code dir=\"ltr\">/settings</code> after a save without stacking a duplicate screen.</p>\n","hints":["The route for a folder itself (<code dir=\"ltr\">/</code> or <code dir=\"ltr\">/settings</code>) comes from a file with the same name in both places.","Layout files and the not-found file have special prefixes: an underscore and a plus sign.","The header’s back arrow does the same thing as the method you need."],"explanation":"<p><code dir=\"ltr\">index.tsx</code> renders a folder’s own URL, so both <code dir=\"ltr\">/</code> and <code dir=\"ltr\">/settings</code> come from an <code dir=\"ltr\">index</code> file. <code dir=\"ltr\">units.tsx</code> inside <code dir=\"ltr\">settings/</code> becomes <code dir=\"ltr\">/settings/units</code>. <code dir=\"ltr\">_layout.tsx</code> wraps its sibling routes in a navigator, and <code dir=\"ltr\">+not-found.tsx</code> catches unmatched URLs. After saving, <code dir=\"ltr\">router.back()</code> pops the units screen and reveals the settings screen that was already underneath; <code dir=\"ltr\">push('/settings')</code> would stack a second copy.</p>\n","checkLabels":{}},"words":701,"readMinutes":3}