javascriptreactjsstategoogle-maps-react

onGoogleApiLoaded not rendering when state change


I have a <GoogleMapReact> component, and I render some circles on the map by a list of points, using onGoogleApiLoaded:

const tags = [allJobsTag].concat(settings.jobs.filter((job) => !job.deleted));
const [tag, setTag] = useState(allJobsTag);

function renderGeoFences(map, maps) {
    _.map(geoFencesSites, (site) => {
        let circle = new maps.Circle({
            strokeColor: tag.id==='all-jobs'?"orange":'#1aba8b26',
            strokeOpacity: 1,
            strokeWeight: 4,
            fillColor: '#1aba8b1f',
            fillOpacity: 1,
            map,
            center: { lat: Number(site.location.latitude), lng: Number(site.location.longitude) },
            radius: site.fenceSize,
        });
    });
}




let apiIsLoaded = (map, maps) => {
    renderGeoFences(map, maps);
};

return(
    <GoogleMapReact>
        zoom={getMapZoom()}
        center={{ lat: centerLatitude, lng: centerLongitude }}
        options={{
            fullscreenControl: false,
            zoomControlOptions: { position: 3 },
        }}
        yesIWantToUseGoogleMapApiInternals
        onGoogleApiLoaded={({ map, maps }) => apiIsLoaded(map, maps)}
    >
        {renderAddresses()}
        {renderUsersLocation()}
        {renderHighlightedUserRoute()}
    </GoogleMapReact>
)

and then rendering the circles in renderGeoFences.

However, this function is only called ones, and even though there are states in it, the circles would not be affected by the state. like in this example, when I try to change to color of the circles by the tag.id (tag is a state). How can I make this function render again when a state is changing?


Solution

  • I suppose you can maintain and googleMapObj which we can use to call isApiLoaded function. And as mentioned below this is called in useEffect.

    const tags = [allJobsTag].concat(settings.jobs.filter((job) => !job.deleted));
    const [tag, setTag] = useState(allJobsTag);
    const [googleApiObj, setIsGoogleApiLoadedObj] = useState(null);
    
    useEffect(() => {
      if (googleApiObj) {
        const {
          map,
          maps
        } = googleApiObj;
        // or else call that isApiLoaded function and pass-on these arguments  
        renderGeoFences(map, maps)
      }
    }, [googleApiObj, tag])
    
    function renderGeoFences(map, maps) {
      _.map(geoFencesSites, (site) => {
        let circle = new maps.Circle({
          strokeColor: tag.id === 'all-jobs' ? "orange" : '#1aba8b26',
          strokeOpacity: 1,
          strokeWeight: 4,
          fillColor: '#1aba8b1f',
          fillOpacity: 1,
          map,
          center: {
            lat: Number(site.location.latitude),
            lng: Number(site.location.longitude)
          },
          radius: site.fenceSize,
        });
      });
    }
    
    return ( <
      GoogleMapReact >
      zoom = {
        getMapZoom()
      }
      center = {
        {
          lat: centerLatitude,
          lng: centerLongitude
        }
      }
      options = {
        {
          fullscreenControl: false,
          zoomControlOptions: {
            position: 3
          },
        }
      }
      yesIWantToUseGoogleMapApiInternals onGoogleApiLoaded = {
        ({
          map,
          maps
        }) => setIsGoogleApiLoaded({
          map,
          maps
        })
      } >
      {
        renderAddresses()
      } {
        renderUsersLocation()
      } {
        renderHighlightedUserRoute()
      } <
      /GoogleMapReact>
    )