React: How to use user current-location's update state not initial state

573 Views Asked by At

I am using React-native-maps for my app. I made fake json restaurants' data and fetched that data, display on my maps by using Marker. In React-native-maps there is one props name initialRegion where I put hard coded initial-state. I used expo-location & expo-permission to display user's current location.

I want to display the distances between user's current location and the restaurants and for that I have used one package called geolib. All the logic works fine. But the problem is when I render the app, it display users' hard coded initial-state and after 5 seconds later the state get update then I can see the accurate current location. I want to wait for the user current location's update state. But I don't know how to do that.

I also share my code in Expo-Snack. Ps: it only works on Android and ios' on snack This is my code

    import React, {useState, useEffect,useCallback} from 'react';
import { Dimensions, StatusBar, StyleSheet, Text,
  TextInput, TouchableOpacity, View, Button, FlatList } from 'react-native';
import Mapview,{ Marker, Callout, PROVIDER_GOOGLE} from 'react-native-maps' 
import * as Location from 'expo-location';
import * as Permissions from 'expo-permissions';
import datas from './components/datas.json'
import { getDistance, getPreciseDistance } from 'geolib';

export default function App() {
  const [state, setstate] = useState({
    "latitude": 60.1098678,
    "longitude": 24.7385084,
    "latitudeDelta": 1,
    "longitudeDelta": 1
  });

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

  const _onMapReady = useCallback(async () => {
    const { status } = await Permissions.askAsync(Permissions.LOCATION);
    if (status !== `granted`) {
    }
    const location = await Location.getCurrentPositionAsync({ "accuracy": Location.Accuracy.High });
    setstate({
      ...state,
      "latitude": location.coords.latitude,
      "longitude": location.coords.longitude
    });
  }, [state]);
    const { latitude, longitude } = state;
       const propertiesInRegion = datas.data.map((location) => {
        const dis = getPreciseDistance( 
          { "latitude": location.location.lat, "longitude": location.location.lng },
          { latitude, longitude }

        );
        return {
          ...location,
          "distance": dis / 1000 
        };
      });

  return (
    <View style={styles.container}>
    <Mapview
        provider={PROVIDER_GOOGLE}
        initialRegion={state}
        showsIndoors={true}
        showsMyLocationButton={true}
        zoomControlEnabled={true}
        zoomEnabled={true}
        zoomTapEnabled={true}
        showsScale={true}
        showsBuildings={true}
        showsUserLocation={true}
        showsCompass={true}
        onMapReady={_onMapReady}
    
        style={styles.mapStyle}>
        {
          datas.data?.map((i) => {
            return (
              <Marker
                coordinate={{
                  "latitude": i.location.lat,
                  "longitude": i.location.lng
                }}
                animation={true}
                key={i.id}
               
              >
                <Callout
                  style={{ "width": 100, "height": 50 }}>
                  <View>
                    <Text>{i.Property}</Text>
                  </View>
                </Callout>
              </Marker>
            );
          })
        }
        
      </Mapview>

      
      <FlatList
       style={styles.flatList}
       data={propertiesInRegion}
       renderItem={({item})=>{
         return <React.Fragment>
         <Text style={styles.text}>{item?.Property}</Text>
         <Text>{item.distance}</Text>
         </React.Fragment>
       }}
      />
     
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    "flex": 1,
    "alignItems": `center`,
    "justifyContent": `center`

  },
 text:{
    color: "white", 
    fontSize:15,
    marginBottom:10
  },
 
  mapStyle: {
    "height": Dimensions.get(`window`).height,
    "width": Dimensions.get(`window`).width
  },
  flatList: {
    "position": `absolute`,
    "bottom": 32,
    "width": 300,
    "height": 200,
    "borderRadius": 24,
    "justifyContent": `center`,
    "alignItems": `center`, 
    backgroundColor:"#5F4B8BFF",
    
  }, 
 
});
1

There are 1 best solutions below

2
Krisna On

@HussainSherwani

I made mapRef null and in the Map View I pass the ref={mapRef} then called it like this:

  const mapRef = React.useRef(null);
  useEffect(() => {
    animateToRegion();
  },
  [state, animateToRegion]);
  const animateToRegion = useCallback(() => {
    mapRef?.current?.animateToRegion(state, 1000);
  }, [state]);
I used optional chaining to remove the error of undefined. But the problem it still shows the intial-state. How can I show the ActivityIndicator while state is updating.