Skip to content

Finding Starbucks in Manhattan

Posted on:August 11, 2025

Welcome, Developer! 👋

Let’s build a simple map app from scratch. We’ll use Expo, TypeScript, and the excellent react-native-maps library. Our app will show a map of Manhattan, New York, with some mock Starbucks locations.

In this tutorial you’ll learn how to:

How does that sound? Let’s dive in!

Create a new Expo project

We’ll start fresh with Expo’s default TypeScript template:

npx create-expo-app@latest

Choose a name (e.g., starbucks-manhattan-map) and select the default Expo template if prompted.

Then open the folder and start the dev server:

cd starbucks-manhattan-map
npm run start

This opens Expo Dev Tools, where you can run the app on iOS, Android, or Expo Go.

Install the Maps library

We’ll use the library react-native-maps to implement a map in our app. With Expo, you install it like this:

npx expo install react-native-maps

That’s it for iOS. On Android, you may need a Google Maps API key to see map tiles. You can create one in the Google Cloud Console, enable the “Maps SDK for Android” and “Maps SDK for iOS” APIs, then add the key to your app.json:

{
  "expo": {
    "android": {
      "config": {
        "googleMaps": {
          "apiKey": "YOUR_ANDROID_GOOGLE_MAPS_API_KEY"
        }
      }
    }
  }
}

Expo has a good step-by-step guide on how to generate your Google Maps API key. It’s a simple step, developer!

Create mock Starbucks data

We’ll store our Starbucks locations in a separate file for clarity. Create a folder called data and then a file called shops.ts:

// data/shops.ts
 
export type CoffeeShop = {
  id: string;
  name: string;
  latitude: number;
  longitude: number;
};
 
export const SHOPS: CoffeeShop[] = [
  {
    id: "1",
    name: "Starbucks – Times Square",
    latitude: 40.758,
    longitude: -73.9855,
  },
  {
    id: "2",
    name: "Starbucks – Bryant Park",
    latitude: 40.7536,
    longitude: -73.9832,
  },
  {
    id: "3",
    name: "Starbucks – Herald Sq",
    latitude: 40.7496,
    longitude: -73.987,
  },
  {
    id: "4",
    name: "Starbucks – Union Sq",
    latitude: 40.7359,
    longitude: -73.9911,
  },
  {
    id: "5",
    name: "Starbucks – Columbus Cir",
    latitude: 40.7681,
    longitude: -73.9819,
  },
  {
    id: "6",
    name: "Starbucks – Grand Central",
    latitude: 40.7527,
    longitude: -73.9772,
  },
];

Code breakdown

  1. We created a TypeScript type called CoffeeShop to represent the mock data.
  2. We created an array of type CoffeeShop to represent the list of Starbucks.

Add the map

Now let’s replace the default app/(tabs)/index.tsx with this code:

import { SHOPS } from "@/data/shops";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
import { useRef } from "react";
import { Platform, Pressable, StyleSheet, Text, View } from "react-native";
import MapView, {
  Callout,
  Marker,
  PROVIDER_DEFAULT,
  Region,
} from "react-native-maps";
import { useSafeAreaInsets } from "react-native-safe-area-context";
 
const MANHATTAN_REGION: Region = {
  latitude: 40.7831,
  longitude: -73.9712,
  latitudeDelta: 0.15,
  longitudeDelta: 0.15,
};
 
export default function HomeScreen() {
  const mapRef = useRef<MapView | null>(null);
  const insets = useSafeAreaInsets();
  const tabBarHeight = useBottomTabBarHeight();
 
  const recenter = () => {
    mapRef.current?.animateToRegion(MANHATTAN_REGION, 800);
  };
 
  return (
    <View style={styles.container}>
      <MapView
        ref={mapRef}
        style={StyleSheet.absoluteFill}
        provider={PROVIDER_DEFAULT}
        initialRegion={MANHATTAN_REGION}
      >
        {SHOPS.map((shop) => (
          <Marker
            key={shop.id}
            coordinate={{
              latitude: shop.latitude,
              longitude: shop.longitude,
            }}
            title={shop.name}
            description="Open daily"
            pinColor="green"
          >
            <Callout>
              <View style={styles.callout}>
                <Text style={styles.calloutTitle}>{shop.name}</Text>
                <Text>One of many in Manhattan ☕</Text>
              </View>
            </Callout>
          </Marker>
        ))}
      </MapView>
 
      <View
        pointerEvents="box-none"
        style={[
          styles.fabWrapper,
          {
            bottom: tabBarHeight + insets.bottom + 16,
          },
        ]}
      >
        <Pressable onPress={recenter} style={styles.fab}>
          <Text style={styles.fabText}>Zoom to Manhattan</Text>
        </Pressable>
      </View>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: "#fff" },
  callout: { maxWidth: 220, gap: 4 },
  calloutTitle: { fontWeight: "600", marginBottom: 2 },
  fabWrapper: {
    position: "absolute",
    left: 0,
    right: 0,
    alignItems: "center",
    zIndex: 10, // iOS + Android stacking
    ...(Platform.OS === "android" ? { elevation: 10 } : null),
  },
  fab: {
    paddingHorizontal: 16,
    paddingVertical: 12,
    backgroundColor: "#1e40af",
    borderRadius: 24,
    shadowColor: "#000",
    shadowOpacity: 0.2,
    shadowRadius: 8,
    elevation: 3,
  },
  fabText: { color: "white", fontWeight: "600" },
});

Code Breakdown

Let’s walk through what’s happening here, step by step.

Imports

We grab everything we need:

  1. React hooks (useRef) to remember our map.
  2. React Native UI (View, Text, Pressable, etc.) to build the layout and button.
  3. Safe area + tab bar helpers (useSafeAreaInsets, useBottomTabBarHeight) so our button floats above the nav bar and iOS home indicator.
  4. Map components from react-native-maps to render the map and control it.
  5. TypeScript type for the map so useRef knows exactly what it’s holding.

Manhattan region

A fixed object that says: “Start the map here, zoomed so all of Manhattan fits nicely.”

The latitudeDelta and longitudeDelta control the zoom level — smaller values mean closer zoom.

Map reference

The mapRef is like a magic string tied to our <MapView>. We use it as a reference to say:

“Hey map, move over here!”

Safe area & tab bar height

The insets.bottom is the padding needed for iOS home indicator areas.

The tabBarHeight is the height of the bottom nav bar.

We add both together so the button never hides under them.

Recenter function

When the button is pressed, we call:

mapRef.current?.animateToRegion(MANHATTAN_REGION, 800);

This tells the map:

“Fly back to Manhattan in 0.8 seconds.”

The layout

The <MapView> fills the whole screen. While the <View style={fabWrapper}> sits on top of the map (absolute position) and holds the button.

The pointerEvents="box-none" lets you still drag the map even if you start the touch near the button’s container.

The <Pressable> is the actual blue button. When tapped it recenter to the Manhattan region.

Styles

  1. container → fills the screen.
  2. fabWrapper → absolutely positions the button overlay.
  3. fab → blue rounded button with padding and a shadow.
  4. fabText → white bold text for the button label.

Run the app

Start the project:

npx expo start

You should see:

  1. A map centered on Manhattan
  2. Green pins for our Starbucks locations
  3. Callouts when you tap a pin
  4. A floating button to zoom back to Manhattan

What’s next

That’s it — you’ve got an App with a Map feature! Nice work, developer đŸ«Ą

From here you could:

  1. Add clustering for many markers
  2. Use your actual location with Expo Location (expo-location)
  3. Fetch real Starbucks data from an API

Conclusion

Maps are one of those features that instantly make your app feel more dynamic and useful. Now you have a setup you can reuse in any project — just swap out the data, tweak the styling, and you’re ready to go.

See you in the next one, Developer. Enjoy the journey and have fun! 💙