0

I have a Google Map and I am trying to update the map center with a Google Autocomplete search. I have the Searchbar in a separate JSX file from the recenter map function. How can I call this function from within my searchbar file? Below is what I tried, with this I get the error TypeError: __WEBPACK_IMPORTED_MODULE_1__map__.a.recenterMap is not a function on the line with the comment above it

Here is my working example, and here is my code(updated based off AlainIb's response):

map.js:

export class MapContainer extends React.Component {
  ...
  recenterMap(lat, lng) {
    const map = this.map;

    const google = this.props.google;
    const maps = google.maps;

    if (map) {
      let center = new maps.LatLng(lat, lng);
      map.panTo(center);
    }
  }
  ...
}
export default MapContainer;

And here is my searchbar.jsx file:

import MapContainer from './map';
/* global google */

class SearchBar extends Component {
  ...
  handlePlaceChanged(){
    const place = this.autocomplete.getPlace();
    this.setState({ lat: place.geometry.location.lat() });
    this.setState({ lng: place.geometry.location.lng() });
    /* WHAT I TRIED */
    MapContainer.recenterMap(this.state.lat, this.state.lng);
  }
  ...
}

export default SearchBar;
user13286
  • 3,027
  • 9
  • 45
  • 100

2 Answers2

1

You cannot do that. A class who extends React.Component can only be called as component ( in jsx with <MapContainer /> or with routing as part of TabNavigator or StackNavigator etc )

1) You can do something like this : add a callback function inside SearchBar component who will be called when handlePlaceChanged() is called to set in state lat and lng, who will be passed as props to the map components

  • in map.js

    export class MapContainer extends React.Component {
      ...
      recenterMap() {             
         const {lat,lng} = this.props;
         ...
      }
     shouldComponentUpdate(nextProps) {
             const diffLat= this.props.lat!== nextProps.lat;
             const diffLng = this.props.done !== nextProps.lng
             return diffLat|| diffLng ;
     }
      ...
    }
    
  • in SearchBar.js

    export class SearchBar extends React.Component {
       ...
        handlePlaceChanged {
          ...
           this.props.updateParentState(lat, lng);
        }
    
      ...
    }
    
  • in the parent component

    <SearchBar updateParentState={(lat,lng)=>{this.setState({ lat,lng }) }} />
    <MapContainer  lat={this.state.lat} lng={this.state.lng} />   
    

2) if maps.js doesn't have a render function, change it as function

export function recenterMap(lat, lng,map,google) {
    // pure logic
} 
AlainIb
  • 4,544
  • 4
  • 38
  • 64
  • Thank you, but how would I then go about firing the `recenterMap` function so that the map then pans to the new props? – user13286 Nov 13 '19 at 00:49
  • [Here's a working example](https://codesandbox.io/s/inspiring-ellis-iirgy). If I add lat/lng to the MapContainer, i get an error – user13286 Nov 13 '19 at 01:08
  • look her : https://codesandbox.io/s/clever-moser-4oh6j it was working before i forked your sandbox, now api key now fail – AlainIb Nov 13 '19 at 10:13
  • Thank you, I have updated the code in my sandbox, but now I am getting `InvalidValueError: setCenter: not a LatLng or LatLngLiteral with finite coordinates: in property lat: NaN is not an accepted value` sorry about the API key, its restricted to this specific sandbox – user13286 Nov 13 '19 at 23:30
  • you did a good think to block api key to this url. it's more a google maps error now :) . lat & lon should be int, NaN mean "not a number", log what you are passing to setCenter, maybe null,null in init state – AlainIb Nov 14 '19 at 07:25
  • in your codesandbox SearchResults/index.js is wrong. you don't put lat & long props. `` – AlainIb Nov 14 '19 at 07:31
  • and add constructor(props) { super(props); this.state = { lat: 0, lng: 0 }; } to SearchResults https://codesandbox.io/s/wonderful-snyder-wbz91 – AlainIb Nov 14 '19 at 07:35
  • Working perfectly now, thank you so much for all the help!! – user13286 Nov 14 '19 at 20:29
  • 1
    glad it help. btw why you called "searchbar.jsx" , i think it should be "searchbar.js" because it's a component files as map.js no ? – AlainIb Nov 14 '19 at 22:42
0

If you want to share the functionality. Assuming, recenterMap does not need to share the state. You can take recenterMap function out of the component, into some other utility class. Pass the required data as arguments to this function.

class ComponentUtility {
static recenterMap(lat, lng, propGoogle) {
    const map = this.map;
    const maps = propGoogle.maps;

    if (map) {
        let center = new maps.LatLng(lat, lng);
        map.panTo(center);
    }
}

}

You can call this static method like:

ComponentUtility.recenterMap(lat, lng, propGoogle);

You just need to pass the right values.

Rajesh Dwivedi
  • 382
  • 2
  • 13
  • Unfortunately I get the same error if I take it outside of the class. [Here's a working example of my code](https://codesandbox.io/s/inspiring-ellis-iirgy) – user13286 Nov 13 '19 at 01:18