React Native Maps and Location

Location and maps turn a generic app into a place-aware experience. React Native can read the device's GPS position and display an interactive map with custom markers. This topic covers getting the user's location and showing it on a map.

The Two Key Packages

Package                    Purpose
────────────────────────────────────────────────────────────
expo-location              Read GPS coordinates, watch position
react-native-maps          Display an interactive map with markers
npx expo install expo-location
npx expo install react-native-maps

Getting the User's Location

Location access requires permission. The device sends the app a latitude and longitude pair. Think of it as the phone saying "I am at this exact point on a globe."

import * as Location from 'expo-location';
import { useState, useEffect } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';

export default function LocationScreen() {
  const [location, setLocation] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    getLocation();
  }, []);

  async function getLocation() {
    const { status } = await Location.requestForegroundPermissionsAsync();

    if (status !== 'granted') {
      setError('Location permission denied.');
      setLoading(false);
      return;
    }

    const pos = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.High,
    });

    setLocation(pos.coords);
    setLoading(false);
  }

  if (loading) return <ActivityIndicator size="large" style={{ flex: 1 }} />;
  if (error)   return <Text>{error}</Text>;

  return (
    <View style={{ padding: 20 }}>
      <Text>Latitude:  {location.latitude.toFixed(6)}</Text>
      <Text>Longitude: {location.longitude.toFixed(6)}</Text>
      <Text>Accuracy:  {Math.round(location.accuracy)} meters</Text>
    </View>
  );
}
Accuracy levels:
Location.Accuracy.Lowest    → coarse (city level, battery-friendly)
Location.Accuracy.Balanced  → neighbourhood level (default)
Location.Accuracy.High      → street level
Location.Accuracy.Highest   → GPS lock (most battery usage)

Displaying a Map

MapView from react-native-maps shows an interactive map. Give it a starting position with initialRegion.

import MapView, { Marker } from 'react-native-maps';

export default function MapScreen() {
  const [location, setLocation] = useState(null);

  useEffect(() => {
    (async () => {
      const { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') return;
      const pos = await Location.getCurrentPositionAsync({});
      setLocation(pos.coords);
    })();
  }, []);

  if (!location) return <ActivityIndicator size="large" style={{ flex: 1 }} />;

  return (
    <MapView
      style={{ flex: 1 }}
      initialRegion={{
        latitude: location.latitude,
        longitude: location.longitude,
        latitudeDelta: 0.01,    // zoom level (smaller = more zoomed in)
        longitudeDelta: 0.01,
      }}
    >
      <Marker
        coordinate={{ latitude: location.latitude, longitude: location.longitude }}
        title="You are here"
        description="Your current location"
      />
    </MapView>
  );
}
latitudeDelta / longitudeDelta — Zoom Guide:
0.001  → street level (one city block)
0.01   → neighbourhood level
0.1    → city level
1.0    → region/state level
10.0   → country level

Map with Multiple Markers

const restaurants = [
  { id: '1', name: 'The Curry House', lat: 28.6139, lng: 77.2090, rating: 4.5 },
  { id: '2', name: 'Pizza Palace',    lat: 28.6150, lng: 77.2100, rating: 4.2 },
  { id: '3', name: 'Noodle Bar',      lat: 28.6125, lng: 77.2080, rating: 4.7 },
];

<MapView style={{ flex: 1 }} initialRegion={{ latitude: 28.6139, longitude: 77.2090, latitudeDelta: 0.02, longitudeDelta: 0.02 }}>
  {restaurants.map((r) => (
    <Marker
      key={r.id}
      coordinate={{ latitude: r.lat, longitude: r.lng }}
      title={r.name}
      description={`Rating: ${r.rating} ⭐`}
    />
  ))}
</MapView>
Map View:
┌──────────────────────────────────────┐
│                                      │
│      📍 The Curry House              │
│                  📍 Pizza Palace     │
│   📍 Noodle Bar                      │
│                                      │
└──────────────────────────────────────┘
  Each 📍 is a Marker component

Custom Marker Pins

<Marker coordinate={{ latitude: 28.6139, longitude: 77.2090 }}>
  <View style={{
    backgroundColor: '#007AFF',
    padding: 8,
    borderRadius: 20,
    borderWidth: 2,
    borderColor: 'white'
  }}>
    <Text style={{ color: 'white', fontSize: 12, fontWeight: 'bold' }}>⭐ 4.5</Text>
  </View>
</Marker>

Watching Position in Real Time

Use watchPositionAsync to get continuous updates as the user moves. Useful for navigation, tracking, or fitness apps.

useEffect(() => {
  let subscription;

  (async () => {
    const { status } = await Location.requestForegroundPermissionsAsync();
    if (status !== 'granted') return;

    subscription = await Location.watchPositionAsync(
      { accuracy: Location.Accuracy.High, distanceInterval: 10 },
      // distanceInterval: only fires when user moves at least 10 metres
      (pos) => {
        setLocation(pos.coords);
      }
    );
  })();

  return () => {
    subscription?.remove();   // stop watching when screen leaves
  };
}, []);

Reverse Geocoding — Coordinates to Address

Coordinates are numbers. Users want to see "123 Main Street, Mumbai". Reverse geocoding converts a latitude/longitude pair into a human-readable address.

async function getAddress(latitude, longitude) {
  const [result] = await Location.reverseGeocodeAsync({ latitude, longitude });

  return `${result.street}, ${result.city}, ${result.region}`;
  // "MG Road, Bengaluru, Karnataka"
}

Forward Geocoding — Address to Coordinates

async function getCoordinates(address) {
  const [result] = await Location.geocodeAsync(address);
  return { latitude: result.latitude, longitude: result.longitude };
}

const coords = await getCoordinates('Taj Mahal, Agra');
// { latitude: 27.1751, longitude: 78.0421 }

Map Types

<MapView mapType="standard"   ... />   // road map (default)
<MapView mapType="satellite"  ... />   // aerial photo
<MapView mapType="hybrid"     ... />   // satellite + road labels
<MapView mapType="terrain"    ... />   // topographic

Summary

Request foreground location permission before reading GPS. getCurrentPositionAsync gives a one-time position. watchPositionAsync gives continuous updates. MapView renders an interactive map and Marker places pins on it. Adjust latitudeDelta and longitudeDelta to control the zoom level. Use reverseGeocodeAsync to convert coordinates into readable addresses.

Leave a Comment