The home screen passed its FlatList header as `ListHeaderComponent={() =>
(...)}`. VirtualizedList renders a function-valued header prop as
`<HeaderComponent />`, so a fresh arrow function on each render is a fresh
element type: React unmounted the entire header subtree — MapView included —
and mounted a new one. Home re-renders several times on mount (useFetch
loading->data, useUserLocation pending->granted, session resolve), and
recreating the Android GoogleMap surface each time left it grey with the
Google logo and tiles that never finished loading.
Pass the header as an element instead so the type stays stable and MapView
mounts once. The same `() => (...)` pattern in ListEmptyComponent here, and in
rides.tsx and confirm-ride.tsx, cost needless remounts of list chrome and
DriverCards; fixed alongside.
Also pin expo-crypto to ~13.0.2. It was ^57.0.1 — a wrong-major native module
for SDK 51 that nothing in the app imports. npm hoisted it to the top level
and gave expo-auth-session a nested 13.0.2 to satisfy its ~13.0.0 constraint,
leaving two copies of one native module in the tree for autolinking to choose
between.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
14 KiB
Ryde - A Full Stack Uber clone using React Native and Expo
📔 Table of Contents
‼️ Folder Structure
Here is the folder structure of Ryde.
uber-clone/
|- .eas/
|-- workflows/
|- app/
|-- (api)/
|-- (auth)/
|-- (root)/
|-- _layout.tsx
|-- +html.tsx
|-- index.tsx
|- assets/
|- components/
|-- custom-button.tsx
|-- driver-card.tsx
|-- google-text-input.tsx
|-- input-field.tsx
|-- map.tsx
|-- oauth.tsx
|-- payment.tsx
|-- ride-card.tsx
|-- ride-layout.tsx
|- config/
|-- index.ts
|- constants/
|-- index.ts
|- lib/
|-- auth.ts
|-- fetch.ts
|-- map.ts
|-- utils.ts
|- scripts/
|-- reset-project.js
|- store/
|-- index.ts
|- types/
|-- image.d.ts
|-- type.d.ts
|- .env.example
|- .env/.env.local
|- .eslintrc.js
|- .gitignore
|- app.json
|- babel.config.js
|- bun.lockb
|- eas.json
|- environment.d.ts
|- nativewind-env.d.ts
|- package.json
|- tailwind.config.js
|- tsconfig.json
🧰 Getting Started
- Make sure Git and NodeJS is installed.
- Clone this repository to your local computer.
- Create
.envfile in root folder. - Contents of
.env:
# .env
# clerk publishable key
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_YOUR_KEY_HERE
# postgres db url (neon db)
DATABASE_URL="postgresql://username:password@hostname:port/uber-clone?sslmode=require"
# expo api server url (you can set it to any random url for development)
EXPO_PUBLIC_SERVER_URL="https://example.com/"
# geoapify api key
EXPO_PUBLIC_GEOAPIFY_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# google api key
EXPO_PUBLIC_GOOGLE_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# areeba payment gateway (credentials issued after merchant onboarding)
AREEBA_API_BASE_URL="https://your-gateway-host.areeba.com"
AREEBA_MERCHANT_ID=your_merchant_id
AREEBA_API_PASSWORD=your_api_password
AREEBA_API_VERSION=100
-
Open terminal in root directory. Run
npm install --legacy-peer-depsoryarn install --legacy-peer-deps. -
Install Expo Cli using
npm i -g expo-clioryarn global add expo-clito run your Expo app.
7. Clerk Publishable Key
- Go to the Clerk Dashboard.
- Sign in or sign up if you don’t have an account.
- Create a new application (or select your existing project).
- Navigate to the "API Keys" section.
- Copy the Publishable Key that starts with
pk_test_. - Add it to your
.envfile:
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_YOUR_KEY_HERE
8. PostgreSQL Database URL (Neon Database)
- Go to the Neon Dashboard.
- Sign in or create an account.
- Create a new project.
- Once the project is created, go to the "Connection Details" section.
- Copy the connection string and replace the placeholder values with your actual database credentials.
- The URL will look something like this:
DATABASE_URL="postgresql://username:password@hostname:port/uber-clone?sslmode=require"
Replace username, password, hostname, and port accordingly.
9. Expo API Server URL
- This can be any URL during development.
- Set it to a random URL for local testing:
EXPO_PUBLIC_SERVER_URL="https://example.com/"
10. Geoapify API Key
- Go to the Geoapify Dashboard.
- Sign up or log in to your account.
- Navigate to the "API Keys" section under your profile.
- Generate a new API key.
- Copy the key and add it to your
.envfile:
EXPO_PUBLIC_GEOAPIFY_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11. Google API Key
- Go to the Google Cloud Console.
- Create a new project (or use an existing one).
- Navigate to the "APIs & Services" section and enable all of the required APIs:
- Maps SDK for Android — draws the map itself. Without it Android renders an empty grey tile area and logcat shows an authorization failure; the app looks like the map "didn't load."
- Maps SDK for iOS — only needed if
components/map.tsxis switched fromPROVIDER_DEFAULT(Apple Maps) toPROVIDER_GOOGLE. - Places API (New) — destination search in
components/google-text-input.tsx. The legacy Places web service is unavailable to newer Google Cloud projects. - Directions API — route polyline and driver ETAs.
- Go to the "Credentials" tab and click on "Create Credentials."
- Select "API Key."
- Copy the generated API Key and add it to your
.envfile:
EXPO_PUBLIC_GOOGLE_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12. Areeba Payment Gateway
- Contact Areeba to open a merchant account (Lebanon).
- After onboarding, Areeba provides your gateway host, merchant ID, API password, and integration docs.
- Add them to your
.envfile:
AREEBA_API_BASE_URL="https://your-gateway-host.areeba.com"
AREEBA_MERCHANT_ID=your_merchant_id
AREEBA_API_PASSWORD=your_api_password
AREEBA_API_VERSION=100
- Now app is fully configured 👍 and you can start using this app using
expo start.
NOTE: Please make sure to keep your API keys and configuration values secure and do not expose them publicly.
📷 Screenshots:
⚙️ Tech Stack
🙌 Contribute
You might encounter some bugs while using this app. You are more than welcome to contribute. Just submit changes via pull request and I will review them before merging. Make sure you follow community guidelines.
💎 Acknowledgements
Useful resources and libraries that are used in Ryde:
- @babel/core: ^7.20.0
- @clerk/clerk-expo: ^2.2.5
- @expo/metro-runtime: ~3.2.3
- @expo/vector-icons: ^14.0.2
- @gorhom/bottom-sheet: ^4.6.4
- @neondatabase/serverless: ^0.9.4
- @react-navigation/native: ^6.0.2
- @stripe/stripe-react-native: ^0.38.4
- @types/jest: ^29.5.12
- @types/react: ~18.2.45
- @types/react-test-renderer: ^18.0.7
- eslint: ^8.57.0
- eslint-config-expo: ^7.1.2
- eslint-config-prettier: ^9.1.0
- eslint-plugin-prettier: ^5.2.1
- expo: ~51.0.28
- expo-constants: ~16.0.2
- expo-font: ~12.0.9
- expo-linking: ^6.3.1
- expo-location: ^17.0.1
- expo-router: ~3.5.23
- expo-secure-store: ^13.0.2
- expo-splash-screen: ~0.27.5
- expo-status-bar: ~1.12.1
- expo-system-ui: ~3.0.7
- expo-web-browser: ~13.0.3
- jest: ^29.2.1
- jest-expo: ~51.0.3
- nativewind: ^2.0.11
- prettier: ^3.3.3
- react: 18.2.0
- react-dom: 18.2.0
- react-native: 0.74.5
- react-native-gesture-handler: ^2.19.0
- react-native-google-places-autocomplete: ^2.5.6
- react-native-maps: ^1.18.0
- react-native-maps-directions: ^1.9.0
- react-native-modal: ^13.0.1
- react-native-reanimated: ~3.10.1
- react-native-safe-area-context: 4.10.5
- react-native-screens: 3.31.1
- react-native-swiper: ^1.6.0
- react-native-web: ~0.19.10
- react-test-renderer: 18.2.0
- stripe: ^16.9.0
- tailwindcss: 3.3.2
- typescript: ~5.3.3
- zustand: ^4.5.5
☕ Buy Me a Coffee
🚀 Follow Me
📚 Learn more
To learn more about developing your project with Expo, look at the following resources:
- Expo documentation: Learn fundamentals, or go into advanced topics with our guides.
- Learn Expo tutorial: Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
⭐ Give A Star
You can also give this repository a star to show more people and they can use this repository.






