Search code examples
javascriptreactjsjsxreact-google-maps

adding useMemo or useCallbacks to the map component breaks the code with error "Rendered more hooks than during the previous render "


what im trying to do

  • place a marker on the map and calculate the distance between the marker and a static location on the map.

problem description

  • previously my useEffect was causing re renders ,now when i try to cache the functions i get this error.
   Unhandled Runtime Error
        Error: Rendered more hooks than during the previous render line 27
  • line 27 is where i use useCallback .

  • placing marker on the map causes effect to run and calculate the distance .

  • All the options provided to GoogleMap component are outside the functional component .

  • To avoid re-creating onMapClick function, i'm trying to use UseCallback which leads to this error . same error with useMemo too .

  • Even if i comment out the onMapClick function and remove it from GoogleMap prop the re rendering issue persists.

    import React, { useState, useEffect, useCallback } from 'react';
    import { GoogleMap, useLoadScript } from '@react-google-maps/api';
    
    const libraries = ['places'];
    const mapContainerStyle = {
      width: '100%',
      height: '40vh',
    };
    const center = {
      lat: 25.33800452203996,
      lng: 55.393221974372864,
    };
    const options = {
      zoomControl: true,
    };
    
    const initialMarker = { lat: null, long: null };
    export default function index() {
      const { isLoaded, loadError } = useLoadScript({
        googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY,
        libraries,
      });
      const [marker, setMarker] = useState(initialMarker);
      if (loadError) return 'Error Loading Maps';
      if (!isLoaded) return 'Loading Maps';
    
      const onMapClick = useCallback((event) => {
        setMarker({
          lat: event.latLng.lat(),
          lng: event.latLng.lng(),
        });
      }, []);
    
      useEffect(() => {
        if (
          google.maps.geometry.spherical.computeDistanceBetween(
            new google.maps.LatLng(center.lat, center.lng),
            new google.maps.LatLng(marker.lat, marker.lng)
          ) > 1000
        ) {
          console.log('out of bounds');
        }
      }, [marker.lat]);
      return (
        <div>
          <GoogleMap
            mapContainerStyle={mapContainerStyle}
            zoom={14}
            options={options}
            center={center}
            onClick={onMapClick}></GoogleMap>
        </div>
      );
    }

reference from similar re-rendering issue

  • i tried this solution too , didnt help .

Solution

  • Your problem is this:

      if (loadError) return 'Error Loading Maps';
      if (!isLoaded) return 'Loading Maps';
    
      const onMapClick = useCallback((event) => {
        setMarker({
          lat: event.latLng.lat(),
          lng: event.latLng.lng(),
        });
      }, []);
    

    The if conditions above may cancel calling some hooks, hence the warning. You shouldn't use hooks conditionally. You need to refactor your code.