Search code examples
javascriptreactjsreact-nativeexporeact-native-maps

How to centre a MapView on a user's current location when the Map Screen is opened? React Native Expo


How to centre the map to show a user's current location when the map screen is opened? By following the expo documentation, it should be achieved with Expo Location API? However, the documentation is unclear. I took part of the code from expo Location documentation and implemented it in my Map Screen. So, how should I integrate it in MapView to execute the getCurrentPositionAsync method and centre the map accordingly when the map screen is opened?

import React, { useContext, useState, useEffect } from "react";
import MapView from "react-native-maps";
import styled from "styled-components";
import { Searchbar } from "react-native-paper";
import { View } from "react-native";

import * as Location from 'expo-location';

const Map = styled(MapView)`
height: 100%;
width: 100%;
`;

const SearchBarContainer= styled(View)`
padding: ${(props) => props.theme.space[3]};
position: absolute;
z-index: 999;
top: 20px;
width: 100%;
`;

export const MapScreen = ({navigation}) => {

  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);

  useEffect(() => {
    (async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      let location = await Location.getCurrentPositionAsync({});
      setLocation(location);
    })();
  }, []);

  return (
    <> 
    <SearchBarContainer>
      <Searchbar placeholder="location"/>
    </SearchBarContainer>
    <Map showsUserLocation={true}>
      
    </Map>
    </>
  );};

Solution

  • I have been struggling with this issue for a couple of days as well and I find it very weird that even though the expo MapView can show your own location on the map, it cannot return your own coördinates.

    Despite that, the problem can be fixed with the following solution.

    1. Install Expo-location

    expo install expo-location

    1. Import it
    import * as Location from 'expo-location'
    
    1. Create a state
    const [location, setLocation] = useState({});
    
    1. Create a useEffect function which retrieves your coördinates asynchronous (retrieving the location at button press may take up to 5-10 seconds which is ridiculously late regarding the user experience)
    useEffect(() => {
            (async () => {
                let { status } = await Location.requestForegroundPermissionsAsync();
                if (status !== 'granted') {
                    return;
                }
    
                let location = await Location.getCurrentPositionAsync({
                    accuracy: Location.Accuracy.Balanced,
                    enableHighAccuracy: true,
                    timeInterval: 5
                });
                setLocation(location);
            })();
        }, []);
    
    1. Your Mapview needs to have a reference to talk to the MapView and set it's coördinates.
    <MapView ref={mapRef}>.... </MapView>
    
    const mapRef = React.createRef();
    
    1. And in the end create a function which can be triggered by a custom button to center to the users location.
    const goToMyLocation = async () => {
            mapRef.current.animateCamera({center: {"latitude":location.coords.latitude, "longitude": location.coords.longitude}});
    }