Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rn-base — React Native + Expo Base Architecture

A production-ready starter I use as the foundation for React Native apps. TypeScript-strict, opinionated, and small enough to read in one sitting.

Built from the patterns I use in production apps (enterprise employee & partner apps shipped to the App Store and Google Play) — rewritten from scratch as a clean, reusable template.

What you get

Concern Choice Why
Language TypeScript (strict) Bugs at compile time, typed navigation params
Framework Expo OTA updates, config plugins, fastest DX
Navigation React Navigation (native stack) Native transitions, typed route map
Server state React Query Caching, retries, loading/error states for free
Client state Zustand Tiny, no boilerplate, works outside React (interceptors)
Storage MMKV Synchronous & ~30x faster than AsyncStorage
Networking Axios + interceptors Auth header injection, normalized errors, 401 auto-logout
i18n i18next Device-locale detection, JSON per language
Theming Design tokens + useTheme Light/dark from one palette, no hardcoded hex

The one rule

Server data lives in React Query. Client state lives in Zustand.

Most RN state-management pain comes from mixing these. Keeping them separate means no manual caches, no stale flags, no "loading" booleans in stores.

Folder structure

src/
├── App.tsx            # provider composition (SafeArea → Query → Navigation)
├── api/               # axios client + interceptors (auth, error normalization)
├── components/        # shared UI (Screen wrapper, AppButton)
├── config/            # env access — fails fast on missing vars
├── i18n/              # i18next setup + locales/en.json, hi.json
├── navigation/        # RootNavigator + typed RootStackParamList
├── query/             # React Query client + per-resource hooks (useUsers)
├── screens/           # feature screens, consume hooks only
├── state/             # Zustand stores (session, persisted via MMKV)
├── storage/           # MMKV instance + Zustand adapter
└── theme/             # design tokens, light/dark, useTheme()

Data flow (end to end)

Screen → useUsers() → React Query → api client → interceptor adds token
                                                    ↑ from Zustand store
   ← loading / error / data states rendered declaratively

A 401 anywhere clears the session store; navigation reacts automatically. Screens never import axios and never parse errors — they get a normalized { status, message }.

Getting started

npx degit rai-ms/rn-base my-app && cd my-app
cp .env.example .env        # set API_BASE_URL
npm install
npm run start

Extending it

  • New API resource → copy src/query/useUsers.ts, change the type + key + path
  • New screen → add to RootStackParamList, register in RootNavigator
  • New language → drop locales/xx.json, register in src/i18n/index.ts
  • Auth flow → call useSessionStore.getState().setSession(token) after login

License

MIT — use it for anything.

About

Production-ready React Native + Expo base architecture — TypeScript, React Query, Zustand, MMKV, i18n, typed navigation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages