Every React Native project hits the wall. Stage 4 is mine.
Up to now, the app has been running in Expo Go — scan a QR code, see the app live on your phone. It is magical and it spoils you. Then you add a native module (in this case expo-sqlite, the local database layer), and Expo Go cannot run it anymore. You need a real build. Which means you need Android Studio. Which means you need Java. Which means you need Gradle. Which means you need your phone plugged in over USB with developer mode enabled.
None of this is conceptually hard. All of it takes longer than you expect.
The sequence of errors was almost comic: no Android SDK found, then no Java runtime, then no device connected, then a Gradle build failure because the local.properties file was missing the SDK path. Each one has a clear fix. None of the error messages tell you what the fix is.
The honest lesson from Stage 4: this is the normal texture of native mobile development. It is not a sign that something is wrong with your project. It is just the tax you pay for shipping to a real device. You pay it once, and then you do not pay it again.
Once the build ran — around five minutes the first time — the app appeared on the Nothing Phone 3a as a real installed app. Not Expo Go with a cosy-reader tab. An actual icon on the home screen.
And then the database worked.
The data model is a repository pattern over expo-sqlite. Two repositories: PublicationRepository and EntryRepository. Each one maps between the camelCase TypeScript types and the snake_case database columns. The hooks — usePublications, useEntries, useEntry — sit on top of the repositories and give the screens a clean async data interface.
The library screen now loads publications from SQLite. The chapter list loads entries from SQLite. The reader loads a specific entry by ID and renders its stored content blocks. The full loop — library to chapter to reader — running on real data from a real local database.
A dev seed function populates the database on first launch during development. Three publications, several entries each. It only runs if the database is empty, so it does not overwrite anything once real data starts coming in from Stage 6.
Stage 4 done. The wall is behind us.

Leave a Reply