{"id":"l-rn-1-2","courseId":"react-native-apps","lang":"en","kind":"lesson","summary":"Create the Trailhead project with create-expo-app, run it on your phone and a simulator, add libraries safely, and know when Expo Go stops being enough.","html":"<p>The React Native docs recommend starting new apps with a framework, and the framework they point to is <strong>Expo</strong>. Expo gives you the project template, the dev server, a library of device APIs (camera, location, storage, notifications) that all work with the same SDK version, and a cloud service to build and ship. You can still write native code when you need to; you’re not locked in.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Create Trailhead</h2>\n<p>You need Node.js (an active LTS release) and a phone or a simulator. Then:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> create-expo-app@latest</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> trailhead</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">cd</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> trailhead</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> expo</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> start</span></span></code></pre></div>\n<p>The default template comes with TypeScript and <strong>Expo Router</strong> already configured. The parts you’ll touch first:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"1\"><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>trailhead/\n  src/app/_layout.tsx    root layout: wraps every screen (navigation lives here)\n  src/app/index.tsx      the first screen, at route &quot;/&quot;\n  src/app/explore.tsx    a second example screen, at &quot;/explore&quot;\n  assets/                icons, splash image, fonts\n  app.json               app name, icons, bundle ids, plugin settings\n  package.json           dependencies, including &quot;expo&quot; (the SDK version)</code></pre></div>\n<p>Every file in <code dir=\"ltr\">src/app</code> becomes a screen. You’ll learn how routing works in section 3; for now, open <code dir=\"ltr\">src/app/index.tsx</code>, change some text, and save.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Run it on a device</h2>\n<p><code dir=\"ltr\">npx expo start</code> launches <strong>Metro</strong>, the JavaScript bundler, and prints a QR code. You have three ways in:</p>\n<ul>\n<li><strong>Your phone with Expo Go.</strong> Install Expo Go from the App Store or Play Store, then scan the QR code (Camera app on iOS, Expo Go itself on Android). The phone and computer must reach each other on the network.</li>\n<li><strong>iOS Simulator</strong> (macOS with Xcode): press <code dir=\"ltr\">i</code> in the terminal.</li>\n<li><strong>Android Emulator</strong> (Android Studio): press <code dir=\"ltr\">a</code>.</li>\n</ul>\n<p>While Metro runs, a few keys earn their place in muscle memory: <code dir=\"ltr\">r</code> reloads the app, <code dir=\"ltr\">m</code> opens the in-app dev menu, and <code dir=\"ltr\">j</code> opens React Native DevTools. Saving a file triggers <strong>Fast Refresh</strong>, which swaps in the new code without losing component state.</p>\n<aside class=\"callout callout-tip\" 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=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Test on a real phone early</span></p>\n<p>A simulator runs on your laptop’s CPU, fakes the camera and GPS (or has none), and gives you no sense of how big a tap target feels under your thumb. Many teams keep a cheap mid-range Android phone on hand for exactly that reason: it shows the slow frames your laptop hides.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">Adding libraries the Expo way</h2>\n<p>Each Expo SDK release targets one React Native version, and native libraries have to match it. So instead of <code dir=\"ltr\">npm install</code>, you add libraries with:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> expo</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> install</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> expo-location</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> expo-image-picker</span></span></code></pre></div>\n<p><code dir=\"ltr\">npx expo install</code> looks up the version that’s known to work with your SDK and installs that one. For pure JavaScript packages (a date library, say) it falls back to your package manager, so you can use it for everything.</p>\n<p>When something feels off after an upgrade, run the health check:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> expo-doctor</span></span></code></pre></div>\n<p>It reports mismatched versions, duplicate native modules and config problems.</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>Installing the latest version of a native library</span></p>\n<p><code dir=\"ltr\">npm install react-native-something@latest</code> can pull a version built for a newer React Native than your project uses. The JavaScript compiles fine, and the app crashes when it calls into native code. Use <code dir=\"ltr\">npx expo install</code> and let it pick.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">Expo Go vs a development build</h2>\n<p><strong>Expo Go</strong> is an app from the store with a fixed set of native modules baked in: the Expo SDK and a handful of popular libraries. Your JavaScript is loaded into it. That’s perfect for learning, and it’s why you could run Trailhead seconds after creating it.</p>\n<p>Its limits show up quickly in real projects:</p>\n<ul>\n<li>It can only include native code that was compiled into it. A library outside that set won’t load.</li>\n<li>It supports one SDK version at a time (usually the latest), so an older project may not open in it.</li>\n<li>Some features need your own app identity, such as push notifications and custom URL schemes.</li>\n</ul>\n<p>A <strong>development build</strong> is your own app, with your app name, icon, bundle identifier and native modules, plus the same dev tools (Fast Refresh, dev menu, DevTools). You create one locally:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> expo</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> run:ios</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> expo</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> run:android</span></span></code></pre></div>\n<p>or in the cloud, without Xcode or Android Studio on your machine, using EAS Build (section 5). After that, <code dir=\"ltr\">npx expo start</code> serves JavaScript to your development build exactly as it did to Expo Go.</p>\n<p>A sensible default: learn and prototype in Expo Go, then switch to a development build the first time you need something Expo Go doesn’t have. For Trailhead you’ll stay in Expo Go until section 4.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">JavaScript changes vs native changes</h2>\n<p>This distinction runs through the whole course, so name it now. <strong>JavaScript changes</strong> (components, styles, logic) reach a running app through Fast Refresh in development and, later, through over-the-air updates in production. <strong>Native changes</strong> (adding a native module, changing permissions text, the app icon or the bundle identifier in <code dir=\"ltr\">app.json</code>) need a new binary. When a change “doesn’t show up”, ask which kind it was.</p>\n<p>Next you’ll replace the template’s example screen with Trailhead’s first real UI, using React Native’s core components.</p>\n","toc":[{"id":"sec-1","text":"Create Trailhead","level":2},{"id":"sec-2","text":"Run it on a device","level":2},{"id":"sec-3","text":"Adding libraries the Expo way","level":2},{"id":"sec-4","text":"Expo Go vs a development build","level":2},{"id":"sec-5","text":"JavaScript changes vs native changes","level":2}],"takeaways":["<code dir=\"ltr\">npx create-expo-app@latest</code> creates a TypeScript project with Expo Router and file-based routes in <code dir=\"ltr\">src/app</code>.","<code dir=\"ltr\">npx expo start</code> runs the Metro dev server; scan the QR code with Expo Go, or press <code dir=\"ltr\">i</code> or <code dir=\"ltr\">a</code> for a simulator or emulator.","Install libraries with <code dir=\"ltr\">npx expo install</code>, which picks the version that matches your Expo SDK.","Expo Go is a learning sandbox with a fixed set of native modules; a development build is your own app with dev tools, and real projects move to one early."],"further":[{"title":"Create a project","url":"https://docs.expo.dev/get-started/create-a-project/"},{"title":"Start developing","url":"https://docs.expo.dev/get-started/start-developing/"},{"title":"Introduction to development builds","url":"https://docs.expo.dev/develop/development-builds/introduction/"}],"quiz":[{"q":"<p>You need <code dir=\"ltr\">expo-location</code> in Trailhead. Which command should you run?</p>","options":[{"text":"<code dir=\"ltr\">npm install expo-location@latest</code>","why":"The latest version may target a newer SDK than your project, which leads to native mismatches that only show up at runtime."},{"text":"<code dir=\"ltr\">npx expo install expo-location</code>","why":"Correct. It installs the version that is known to work with your project’s Expo SDK."},{"text":"<code dir=\"ltr\">npx expo add-module expo-location</code>","why":"There’s no <code dir=\"ltr\">add-module</code> command. <code dir=\"ltr\">npx expo install</code> is the one to remember."}],"answer":1},{"q":"<p>Trailhead adds a library with custom native code that isn’t part of Expo Go. What’s the right next step?</p>","options":[{"text":"Keep using Expo Go and wait for it to load the module over the network.","why":"Expo Go can’t download native code. Its native modules are fixed when the app is built and published to the stores."},{"text":"Eject from Expo and maintain the ios and android folders by hand.","why":"There’s no need. Expo projects can include any native library; you just build your own app binary."},{"text":"Create a development build, either locally with <code dir=\"ltr\">npx expo run:ios</code> or in the cloud with EAS Build.","why":"Correct. A development build is your own app with your native modules plus the dev tools you had in Expo Go."}],"answer":2},{"q":"<p>You edit the title text in <code dir=\"ltr\">src/app/index.tsx</code> and save. What happens on the phone running the app?</p>","options":[{"text":"Fast Refresh swaps in the new code and keeps component state where it can.","why":"Correct. JavaScript changes reload in place in about a second; only native changes need a new build."},{"text":"Nothing until you rebuild the app binary.","why":"Rebuilding is only needed for native changes such as new native modules or app.json settings that change the binary."},{"text":"The app restarts from the splash screen and loses all state.","why":"That’s a full reload, which you can trigger with <code dir=\"ltr\">r</code>, but saving a file uses Fast Refresh."}],"answer":0}],"exercise":{"kind":"fill","language":"bash","template":"# 1. Create the project\nnpx {{0}}@latest trailhead\ncd trailhead\n\n# 2. Start the dev server (Metro)\nnpx expo {{1}}\n\n# 3. Add GPS support at the version that matches your SDK\nnpx expo {{2}} expo-location\n\n# 4. Check the project for version mismatches\nnpx {{3}}\n\n# 5. Build and run a development build on the iOS Simulator\nnpx expo {{4}}","blanks":[{"answers":["create-expo-app"]},{"answers":["start"]},{"answers":["install"]},{"answers":["expo-doctor","expo-doctor@latest"]},{"answers":["run:ios"]}],"title":"The Expo commands you'll type every week","prompt":"<p>Fill in the blanks so this terminal session creates Trailhead, starts the dev server, adds <code dir=\"ltr\">expo-location</code> safely, runs the health check, and then builds a development build for the iOS Simulator.</p>\n","hints":["The project generator’s package name is the thing you’d search npm for to create an Expo app.","Adding a native library uses the same verb as npm, but through <code dir=\"ltr\">npx expo</code>.","Building locally for a platform uses <code dir=\"ltr\">run:</code> followed by the platform name."],"explanation":"<p><code dir=\"ltr\">npx create-expo-app@latest</code> scaffolds the project, <code dir=\"ltr\">npx expo start</code> runs Metro, and <code dir=\"ltr\">npx expo install</code> picks the library version that matches your SDK. <code dir=\"ltr\">npx expo-doctor</code> checks for mismatches. <code dir=\"ltr\">npx expo run:ios</code> compiles your own app binary (a development build) and installs it on the simulator, which you need once Expo Go doesn’t have a native module you use.</p>\n","checkLabels":{}},"words":757,"readMinutes":4}