Building the app
The reorder app now has a spec, a tested flow and an API. In this lesson you build the part shop owners hold in their hands: a React Native app made with Expo that shows the last orders, repeats one with adjusted quantities and never loses or doubles an order on a weak mobile signal.
By the end you can
- Run an Expo app on your own phone and connect it to the API on your laptop
- Turn the flow from app-02 into screens with file-based routes
- Give every request a timeout and four clear states: loading, ready, empty and error
- Make the Place order button safe to tap twice and safe to retry, with an idempotency key
The everyday picture
Think of a waiter in a busy restaurant. The waiter does not cook. The waiter carries orders to the kitchen, brings food back and keeps the table informed: "your food is on its way", "the kitchen is out of fish, would you like chicken?" A good waiter never stands silent at the table while the customer wonders what is happening.
Now the kitchen is loud, and the waiter is not sure the cook heard the order. A bad waiter shouts the order again, and two plates of rice arrive. A good waiter writes a slip number on every order. If in doubt, the waiter asks "did you get slip 17?" The cook checks the slip and either starts cooking or says "already on the stove".
Your app is the waiter. The API is the kitchen. The mobile network is the noise. This lesson is about keeping the shop owner informed on every screen and putting a slip number on every order.
How the phone finds your code and your API
Expo is a toolkit around React Native. You write screens in TypeScript with React components such as View, Text and Button, and they become real native screens on Android and iPhone. While you develop, you do not build an app file at all. You run npx expo start on your laptop, and a program called Metro packs your code into a bundle. You open Expo Go on your phone, scan the QR code in the terminal, and the phone downloads the bundle and runs it.
So there are two separate trips over your Wi-Fi. The first carries your code from Metro to the phone. The second happens every time a screen needs data: the app running on the phone calls your API, which runs on the same laptop on port 3000.
The second trip is where most beginners get stuck. On your laptop, http://localhost:3000 means "this laptop". Inside the app on the phone, localhost means "this phone", and nothing is listening there. You must use your laptop's LAN IP address instead, for example http://192.168.1.20:3000, and the phone must be on the same Wi-Fi. The Android emulator is a special case: it reaches your laptop at 10.0.2.2.
Do not type that address into your code. Put it in a .env file as EXPO_PUBLIC_API_URL. Expo reads variables that start with EXPO_PUBLIC_ and writes their values into the bundle when it builds it. Later, in Continuous delivery, the same line will point at a staging API for test builds and at production for real ones. Because the value is written into the app, anyone who unpacks the app can read it. An API address is fine there. A secret key is not: secrets stay on the server.
EXPO_PUBLIC_API_URL.Quick check
The API answers curl http://localhost:3000/v1/orders on your laptop, but in Expo Go on your phone the orders screen fails at once with a network error. What is the most likely cause?
Expo Go makes network requests normally, and res.json() reads JSON. The failure is the address: on the phone, localhost points at the phone, where no API is running. Use the laptop's LAN IP in EXPO_PUBLIC_API_URL and keep both devices on the same Wi-Fi.