Skip to content

TypeError: Cannot read properties of undefined (reading 'x') when show Popup in ReactGLMap #4

@vulinhnopro2704

Description

@vulinhnopro2704

Description

I want to show Pop up in my Map when click to a Marker. I use import ReactMapGL, { Marker, Popup } from '@goongmaps/goong-map-react'; but I got an error and crash the app. I write the same code with the example. Here is my code:

// MapView.tsx
import type { LatLng } from '@/lib/utils';
import { getDistanceKm } from '@/lib/utils';
import ReactMapGL, { Marker, Popup } from '@goongmaps/goong-map-react';
import { MapPin } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
import { SenderMarker } from './SenderMarker';
import { ShipperRoute } from './ShipperRoute';
import type { PlaceDetail } from './type';

interface MapViewProps {
  selectedPlace?: PlaceDetail | null;
}

export function MapView({ selectedPlace }: MapViewProps) {
  const [mounted, setMounted] = useState(false);
  const [mapReady, setMapReady] = useState(false);
  const mapRef = useRef<any>(null);

  useEffect(() => {
    setMounted(true);

    return () => {
      if (mapRef.current) {
        try {
          mapRef.current.getMap?.()?.remove?.();
        } catch {}
      }
    };
  }, []);

  // Check if map is ready by polling mapRef
  useEffect(() => {
    const checkMapReady = () => {
      if (mapRef.current?.getMap?.()) {
        setMapReady(true);
      } else {
        // Keep checking until map is ready
        const timer = setTimeout(checkMapReady, 100);
        return () => clearTimeout(timer);
      }
    };

    if (mounted) {
      checkMapReady();
    }
  }, [mounted]);

  const [sender] = useState<LatLng>({ lat: 21.028, lng: 105.85 });
  const [receiver] = useState<LatLng>({ lat: 21.035, lng: 105.82 });
  const [showSenderPopup, setShowSenderPopup] = useState(false);
  const [showPlacePopup, setShowPlacePopup] = useState(false);

  const [viewState, setViewState] = useState({
    latitude: 21.03,
    longitude: 105.835,
    zoom: 13,
  });

  // Safe handler to show popup only when map is ready
  const handleShowSenderPopup = () => {
    if (mapReady && mapRef.current?.getMap?.()) {
      setShowSenderPopup(true);
    }
  };

  const handleShowPlacePopup = () => {
    if (mapReady && mapRef.current?.getMap?.()) {
      setShowPlacePopup(!showPlacePopup);
    }
  };

  useEffect(() => {
    if (selectedPlace?.geometry.location) {
      setViewState({
        latitude: selectedPlace.geometry.location.lat,
        longitude: selectedPlace.geometry.location.lng,
        zoom: 15,
      });
      if (mapReady) {
        setShowPlacePopup(true);
      }
    }
  }, [selectedPlace, mapReady]);

  const [isDragging] = useState(false);
  const [isHovering] = useState(false);
  const cursor = isDragging ? 'grabbing' : isHovering ? 'pointer' : 'default';

  if (!mounted) {
    return <div className='h-full w-full' />;
  }

  return (
    <ReactMapGL
      ref={mapRef}
      {...viewState}
      viewState={viewState}
      onViewStateChange={(evt: any) => {
        setViewState(evt.viewState);
      }}
      width='100vw'
      height='100vh'
      goongApiAccessToken={import.meta.env.VITE_GOONG_MAPTILES_KEY}
      onResize={() => {}}
      getCursor={() => cursor}
      touchAction='pan-y'
      onLoad={() => setMapReady(true)}
    >
      <SenderMarker location={sender} onClick={handleShowSenderPopup} />
      {mapReady && showSenderPopup && (
        <Popup
          latitude={sender.lat}
          longitude={sender.lng}
          closeOnClick={false}
          onClose={() => setShowSenderPopup(false)}
          captureClick={true}
          captureDrag={true}
          captureScroll={true}
          captureDoubleClick={true}
        >
          <div>
            <strong>Sender:</strong> (Thông tin ...)
            <br />
            <strong>To Receiver:</strong> {getDistanceKm(sender, receiver).toFixed(2)} km
          </div>
        </Popup>
      )}

      <SenderMarker location={receiver} onClick={() => {}} />
      <ShipperRoute origin={sender} destination={receiver} />

      {/* Selected Place Marker */}
      {selectedPlace?.geometry.location && (
        <>
          <Marker
            latitude={selectedPlace.geometry.location.lat}
            longitude={selectedPlace.geometry.location.lng}
            offsetLeft={-12}
            offsetTop={-24}
          >
            <div
              className='cursor-pointer transition-transform hover:scale-110'
              onClick={handleShowPlacePopup}
            >
              <MapPin className='h-6 w-6 text-blue-600 fill-blue-200' />
            </div>
          </Marker>

          {mapReady && showPlacePopup && (
            <Popup
              latitude={selectedPlace.geometry.location.lat}
              longitude={selectedPlace.geometry.location.lng}
              closeOnClick={false}
              onClose={() => setShowPlacePopup(false)}
              anchor='bottom'
              captureClick={true}
              captureDrag={true}
              captureScroll={true}
              captureDoubleClick={true}
            >
              <div className='max-w-xs'>
                <div className='font-semibold text-sm mb-1'>{selectedPlace.name}</div>
                <div className='text-xs text-gray-600 mb-2'>{selectedPlace.formatted_address}</div>
                {selectedPlace.compound && (
                  <div className='text-xs text-gray-500 space-y-0.5'>
                    {selectedPlace.compound.commune && (
                      <div>
                        <strong>Xã/Phường:</strong> {selectedPlace.compound.commune}
                      </div>
                    )}
                    {selectedPlace.compound.district && (
                      <div>
                        <strong>Quận/Huyện:</strong> {selectedPlace.compound.district}
                      </div>
                    )}
                    {selectedPlace.compound.province && (
                      <div>
                        <strong>Tỉnh/TP:</strong> {selectedPlace.compound.province}
                      </div>
                    )}
                  </div>
                )}
                <div className='text-xs text-gray-400 mt-2'>
                  {selectedPlace.geometry.location.lat.toFixed(6)},{' '}
                  {selectedPlace.geometry.location.lng.toFixed(6)}
                </div>
              </div>
            </Popup>
          )}
        </>
      )}
    </ReactMapGL>
  );
}

Repro Steps

Environment (please complete the following information):

  • Library Version: @goongmaps/goong-map-react 1.1.2
  • React Version:19.0.0
  • Vite: 6.3.6
  • Tanstack Router: 1.132.33
  • OS: Window 11.

Logs

TypeError: Cannot read properties of undefined (reading 'x')
    at getContainerStyle (@goongmaps_goong-map-react.js?v=c2c469ee:21796:57)
    at Popup (@goongmaps_goong-map-react.js?v=c2c469ee:21846:24)
    at Object.react_stack_bottom_frame (react-dom_client.js?v=c2c469ee:18509:20)
    at renderWithHooks (react-dom_client.js?v=c2c469ee:5654:24)
    at updateFunctionComponent (react-dom_client.js?v=c2c469ee:7475:21)
    at beginWork (react-dom_client.js?v=c2c469ee:8525:20)
    at runWithFiberInDEV (react-dom_client.js?v=c2c469ee:999:15)
    at performUnitOfWork (react-dom_client.js?v=c2c469ee:12561:98)
    at workLoopSync (react-dom_client.js?v=c2c469ee:12424:43)
    at renderRootSync (react-dom_client.js?v=c2c469ee:12408:13)

The above error occurred in the <Popup> component.

React will try to recreate this component tree from scratch using the error boundary you provided, CatchBoundaryImpl.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions