Home > other >  React Native: Convert class components into functional components
React Native: Convert class components into functional components

Time:05-27

Fortunately, I found a solution about React Native Google Maps with Autocomplete by https://mdmoin07.medium.com/react-native-google-maps-with-autocomplete-45a5617be2f5. I'm able to convert the code using functional components. Initially, my code seems to work to fetch address from react-native-google-maps-autocomplete but unfortunately, the map is not showing and gives an error.

ERROR Warning: Failed prop type: The prop region.latitude is marked as required in MapView, but its value is undefined.

import React, { useEffect, useRef, useState } from 'react';
import { View, StyleSheet } from 'react-native';
//mport RNMapView, { Circle, Marker, Polyline } from 'react-native-maps';
import { getLocation, geocodeLocationByName } from '../services/location-service';
//import MapInput from '../services/MapInput';
import MyMapView from '../components/map/MapView';

import MapInput from '../components/map/MapInput';



import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';
import MapView, { Marker } from 'react-native-maps';



function MapContainer({ coords }) {
  /*
  state = {
    region: {}
  };
*/

  const [region, setState] = useState({});

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


  function getInitialState() {
    getLocation().then(
      (data) => {
        console.log(data);
        setState({
          region: {
            latitude: data.latitude,
            longitude: data.longitude,
            latitudeDelta: 0.003,
            longitudeDelta: 0.003
          }
        });
      }
    );
  }

  function getCoordsFromName(loc) {
    setState(region);
  }

  function onMapRegionChange(region) {
    this.setState({ region });
  }

  return (
    <View style={{ flex: 1 }}>
      <View style={{ flex: 1 }}>
        <GooglePlacesAutocomplete
          placeholder='Search'
          minLength={2} // minimum length of text to search
          autoFocus={true}
          returnKeyType={'search'} // Can be left out for default return key 
          listViewDisplayed={false}    // true/false/undefined
          fetchDetails={true}
          onPress={(data, details = null) => { // 'details' is provided when fetchDetails = true
            getCoordsFromName(details.geometry.location);
            console.log(data);
          }
          }
          query={{
            key: "API KEY",
            language: 'en',
            components: "country:ph",
          }}

          nearbyPlacesAPI='GooglePlacesSearch'
          debounce={300}
        />
      </View>

      {
        region['latitude'] ?
          <View style={{ flex: 1 }}>
            <MapView
              style={{ flex: 1 }}
              ref={mapRef}
              region={region.latitude}
              showsUserLocation={true}
              onRegionChange={(reg) => onMapRegionChange(reg)} >

              <Marker
                coordinate={region.latitude} />
            </MapView>
          </View>


          : null}
    </View>
  );
}

export default MapContainer;

These codes are class components from the reference I found.

import React, { useEffect, useRef, useState} from 'react';
import { View, StyleSheet } from 'react-native';
//mport RNMapView, { Circle, Marker, Polyline } from 'react-native-maps';
import { getLocation, geocodeLocationByName } from '../services/location-service';
//import MapInput from '../services/MapInput';
import MyMapView from '../components/map/MapView';

import MapInput from '../components/map/MapInput';



import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';
import MapView, {Marker} from 'react-native-maps';





class MapContainer extends React.Component {
  state = {
      region: {}
  };

  componentDidMount() {
      this.getInitialState();
  }

  getInitialState() {
      getLocation().then(
          (data) => {
              console.log(data);
              this.setState({
                  region: {
                      latitude: data.latitude,
                      longitude: data.longitude,
                      latitudeDelta: 0.003,
                      longitudeDelta: 0.003
                  }
              });
          }
      );
  }

  getCoordsFromName(loc) {
      this.setState({
          region: {
              latitude: loc.lat,
              longitude: loc.lng,
              latitudeDelta: 0.003,
              longitudeDelta: 0.003
          }
      });
  }

  onMapRegionChange(region) {
      this.setState({ region });
  }

  render() {
      return (
          <View style={{ flex: 1 }}>
              <View style={{ flex: 1 }}>
        <GooglePlacesAutocomplete
                        placeholder='Search'
                        minLength={2} // minimum length of text to search
                        autoFocus={true}
                        returnKeyType={'search'} // Can be left out for default return key 
                        listViewDisplayed={false}    // true/false/undefined
                        fetchDetails={true}
                        onPress={(data, details = null) => { // 'details' is provided when fetchDetails = true
                            this.getCoordsFromName(details.geometry.location);
                            console.log(data);
                        }
                        }
                        query={{
                        key: "API KEY",
                            language: 'en',
                            components: "country:ph",
                        }}

                        nearbyPlacesAPI='GooglePlacesSearch'
                        debounce={300}
                    />
              </View>

              {
                  this.state.region['latitude'] ?


                      <View style={{ flex: 1 }}>
                     <MapView
                        style={{ flex: 1 }}
                        region={this.state.region}
                        showsUserLocation={true}
                        onRegionChange={(reg) => this.onMapRegionChange(reg)} >

                        <Marker
                            coordinate={this.state.region} />
                    </MapView>
                      </View> 
                      
                      
                      : null}
          </View>
      );
  }
}

export default MapContainer;

Thank you for kindly answering my question. I'm from the Philippines. Maraming Salamat po.

CodePudding user response:

I have resolved your issue for converting it class to functional component. Please check the code and try to re run it.

import React, { useEffect, useRef, useState } from "react";
import { View, StyleSheet } from "react-native";
//mport RNMapView, { Circle, Marker, Polyline } from 'react-native-maps';
import {
  getLocation,
  geocodeLocationByName,
} from "../services/location-service";
//import MapInput from '../services/MapInput';
import MyMapView from "../components/map/MapView";
import MapInput from "../components/map/MapInput";
import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete";
import MapView, { Marker } from "react-native-maps";
function MapContainer({ coords }) {
  const [region, setRegion] = useState({
   latitude: '',
   longitude: '',
   latitudeDelta: 0.003,
   longitudeDelta: 0.003,
  });
  useEffect(() => {
    getInitialState();
  }, []);
 function getInitialState() {
    getLocation().then((data) => {
      console.log(data);
  setRegion({
      latitude: data.latitude,
      longitude: data.longitude,
      latitudeDelta: 0.003,
      longitudeDelta: 0.003,
    });
  });
}
function getCoordsFromName(loc) {
 setRegion({
    latitude: loc.latitude,
    longitude: loc.longitude,
    latitudeDelta: 0.003,
    longitudeDelta: 0.003,
  });
}
function onMapRegionChange(getRegion ) {
setRegion(getRegion);
}
 return (
  <View style={{ flex: 1 }}>
   <View style={{ flex: 1 }}>
    <GooglePlacesAutocomplete
      placeholder="Search"
      minLength={2} // minimum length of text to search
      autoFocus={true}
      returnKeyType={"search"} // Can be left out for default return key
      listViewDisplayed={false} // true/false/undefined
      fetchDetails={true}
      onPress={(data, details = null) => {
        // 'details' is provided when fetchDetails = true
        getCoordsFromName(details.geometry.location);
        console.log(data);
      }}
      query={{
        key: "API KEY",
        language: "en",
        components: "country:ph",
      }}
      nearbyPlacesAPI="GooglePlacesSearch"
      debounce={300}
    />
  </View>
  { region ? (
    <View style={{ flex: 1 }}>
      <MapView
        style={{ flex: 1 }}
        ref={mapRef}
        region={region}
        showsUserLocation={true}
        onRegionChange={(reg) => onMapRegionChange(reg)}
      >
        <Marker coordinate={{ latitude : region.latitude , longitude : region.longitude }}/>
      </MapView>
    </View>
  ) : null}
</View>
 );
 }
export default MapContainer;

EDIT Answer

For Google places autocomplete you are getting undefined because you not saving it from correct value from response. Save it like below : (check console.log of data & details as well)

onPress={(data, details = null) => {
   setRegion({
       latitude: details.geometry.location.lat,
       longitude: details.geometry.location.lng,
       latitudeDelta: 0.003,
       longitudeDelta: 0.003,
   });
}}

For map issue you can give any default values in useState for latitude and longitude

const [region, setRegion] = useState({
     latitude: 22.5726,
     longitude: 88.3639,
     latitudeDelta: 1,
     longitudeDelta: 1, 
 });

With the given code I can only get this much idea about your issues, if you are facing the issue after this too, then please provide full code.

CodePudding user response:

Please try initialRegion instead of region in the MapView component and I would also define a whole region object with latitude, longitude and respective deltas.

  • Related