Reputation: 1619
I am trying to create a map with locations fetched from Foursquare API , the locations are displayed in two ways in the app, as a side bar containing a list items (location names) and markers on the map, there is a search box, and depending on the query on this search box data should be filtered so the locations and markers should be filtered to match the query in the same time, now i got the location list filtered correctly but not the markers on the map
here is the parent component
import React, { Component } from 'react';
import Map from './Map';
import List from './List'
import escapeRegExp from 'escape-string-
regexp';
import './App.css';
class App extends Component {
state = {
places: [],
query: '',
}
componentDidMount() {
this.fetchPlaces();
}
fetchPlaces() {
const client_id = "N4UIDVOE5XA3YVMBMMLIANAYLDEGSTDJY3KLFM0BAQJB1A4G" ;
const client_secret = "RVWSHIZAAKLLTW03ELYCPVY1GJ1QZ312AP0C1MLOCBP5JG4Q";
const api = "https://api.foursquare.com";
const request = fetch(`${api}/v2/venues/search?ll=30.044281,31.224291&categoryId=4bf58dd8d48988d181941735,4bf58dd8d48988d181941735,4bf58dd8d48988d13a941735&client_id=${client_id}&client_secret=${client_secret}&v=20180719`);
return request.then(response => {
//MDN
const myOk = response.ok;
if(myOk) {
return response.json();
}
}).then(places => {
this.setState({places: places.response.venues});
//on error fetching locations
}).catch(() => alert('error fetching data'));
}
updateQuery = (query) => {
this.setState({query})
}
render() {
const { places, query} = this.state;
let placesToShow;
if(query) {
const match = new RegExp(escapeRegExp(query), 'i');
placesToShow = places.filter(place => match.test(place.name));
}
else {
placesToShow = places;
}
return (
<div className="app">
<Map places={ placesToShow }/>
<List places ={ placesToShow }
onUpdateQuery={ this.updateQuery }/>
</div>
);
}
}
export default App;
and this is the child component
import React, { Component } from 'react';
class Map extends Component {
componentDidMount() {
//getting the script of the map
const script = document.getElementsByTagName('script')[0];
//load the map after the script loads
script.addEventListener('load', e => {this.initMap()});
}
initMap() {
const container = document.getElementById('map');
const map = new
window.google.maps.Map(container, {
center: { lat: 30.044281, lng: 31.224291 },
});
this.setState({ map });
}
createMarkers() {
const { map } = this.state;
const markers =
this.props.places.map(place => { return (new window.google.maps.Marker({
position: {lat: place.location.lat, lng: place.location.lng},
name: place.name,
map: map,
}));
})
const bounds = new window.google.maps.LatLngBounds();
const largeInfoWindow = new window.google.maps.InfoWindow();
markers.forEach(marker => {
bounds.extend(marker.position);
marker.addListener('click', e => {
largeInfoWindow.setContent(`<div>${marker.name }</div>`);
largeInfoWindow.open(map, marker);
});
})
map.fitBounds(bounds);
}
componentDidUpdate() {
this.createMarkers();
}
render(){
return(
<div id="map" />
);
}
}
export default Map;
so why markers are not filtered correctly, and how to achieve that???
Edit
It worked after i set all markers map to null before adding only the filtered ones
componentDidUpdate(prevProps, prevState) {
if(prevProps.places !== this.props.places) {
this.state.markers.forEach(marker => marker.setMap(null))
this.createMarkers();
}
}
Upvotes: 0
Views: 172
Reputation: 2390
I think the issue is that your createMarkers
function does not remove markers. It only appends new markers and probably duplicates them as well. The easy thing to do would be to remove all markers at the start of createMarkers
using marker.setMap(null)
as described here. This isn't the most efficient solution, however, as you could compare the previous markers with the new markers and only adjust as necessary. Alternatively, you could utilize the react-google-maps library to handle the markers for you.
Upvotes: 2