If you're building a property or travel app with React Native and want to show each listing on a map, this quick guide walks you through adding a simple Google Map — starting with a fixed location and ending with live coordinates from your Supabase database.
🧩 Step 1. Install the Map Library
Expo supports react-native-maps out of the box. Just install it:
npx expo install react-native-maps
This gives you access to an interactive Google Map view and markers for iOS and Android.
🏠 Step 2. Create a Simple Fixed Map
Before connecting to data, start with something static.
import React from 'react';
import { StyleSheet, View } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
export default function HouseDetails() {
const region = {
latitude: -36.8485, // Auckland
longitude: 174.7633,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
};
return (
<View style={styles.container}>
<MapView style={styles.map} initialRegion={region}>
<Marker
coordinate={{ latitude: -36.8485, longitude: 174.7633 }}
title="Sample Home"
description="123 Queen Street, Auckland"
/>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
map: { width: '100%', height: 300, borderRadius: 12 },
});
That’s already enough to render a map centered on Auckland — no API key, no fuss.
⚙️ Step 3. Load Coordinates from Supabase
Let’s make it dynamic by reading each house’s latitude and longitude from your Supabase table.
import React, { useEffect, useMemo, useState } from 'react';
import { ActivityIndicator, StyleSheet, View } from 'react-native';
import { useLocalSearchParams } from 'expo-router';
import MapView, { Marker } from 'react-native-maps';
import { supabase } from '@/lib/supabase';
type House = {
id: string;
title: string | null;
address: string | null;
latitude: number | null;
longitude: number | null;
};
export default function HouseDetails() {
const { id } = useLocalSearchParams<{ id: string }>();
const [house, setHouse] = useState<House | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let mounted = true;
(async () => {
const { data, error } = await supabase
.from('houses')
.select('id, title, address, latitude, longitude')
.eq('id', id)
.single();
if (mounted) {
if (error) console.warn('Failed to load house:', error.message);
setHouse(data ?? null);
setLoading(false);
}
})();
return () => { mounted = false; };
}, [id]);
const region = useMemo(() => {
if (!house?.latitude || !house?.longitude) return null;
return {
latitude: house.latitude,
longitude: house.longitude,
latitudeDelta: 0.02,
longitudeDelta: 0.02,
};
}, [house?.latitude, house?.longitude]);
if (loading)
return <View style={styles.center}><ActivityIndicator /></View>;
if (!region)
return <View style={styles.center} />;
return (
<View style={styles.container}>
<MapView
key={`${region.latitude},${region.longitude}`}
style={styles.map}
initialRegion={region}
showsUserLocation={false}
showsCompass={false}>
<Marker
coordinate={region}
title={house?.title ?? 'Home'}
description={house?.address ?? ''}
/>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
center: { flex: 1, alignItems: 'center', justifyContent: 'center' },
map: { width: '100%', height: 300, borderRadius: 12 },
});
Why use useMemo()?
When coordinates come from asynchronous data, useMemo() ensures the region object stays stable between renders. Without it, the map might flicker or reset each time the component updates.
📦 Database Setup
Make sure your Supabase table has columns like:
| column | type |
|---|---|
| id | uuid |
| title | text |
| address | text |
| latitude | numeric |
| longitude | numeric |
If you only have addresses, you can add a small geocoding helper later to convert them into coordinates automatically.
🧭 Step 4. Optional — Static Placeholder Map
If you prefer a lightweight image (no user interaction), use Google’s Static Maps API instead:
<Image
source={{
uri: 'https://maps.googleapis.com/maps/api/staticmap?center=Auckland,New+Zealand&zoom=13&size=600x300&markers=color:red|Auckland,New+Zealand',
}}
style={{ width: '100%', height: 300, borderRadius: 12 }}
/>
✅ Wrap-Up
You now have a dynamic, interactive map inside your React Native app that reads real data from Supabase.
For small projects, this pattern is simple, fast, and deploy-ready — no Google Cloud setup required.
SOCIAL SHARE CARD GENERATOR