@vis.gl/react-google-maps
Version:
React components and hooks for the Google Maps JavaScript API
108 lines (96 loc) • 3.23 kB
text/typescript
import {Ref, useEffect, useState} from 'react';
import {useCallbackRef} from '../../hooks/use-callback-ref';
import {useMapsLibrary} from '../../hooks/use-maps-library';
import {
CameraStateRef3D,
useTrackedCameraStateRef3D
} from './use-tracked-camera-state-ref-3d';
import {Map3DProps} from './index';
/**
* Hook to manage the Map3DElement instance lifecycle.
*
* Handles:
* - Waiting for the 'maps3d' library to load
* - Waiting for the 'gmp-map-3d' custom element to be defined
* - Creating a callback ref for the element
* - Applying initial options when the element is ready
* - Tracking camera state
*
* @internal
*/
export function useMap3DInstance(
props: Map3DProps
): readonly [
map3d: google.maps.maps3d.Map3DElement | null,
containerRef: Ref<HTMLDivElement>,
map3dRef: Ref<google.maps.maps3d.Map3DElement>,
cameraStateRef: CameraStateRef3D,
isReady: boolean
] {
const maps3dLib = useMapsLibrary('maps3d');
const [customElementReady, setCustomElementReady] = useState(false);
const [, containerRef] = useCallbackRef<HTMLDivElement>();
const [map3d, map3dRef] = useCallbackRef<google.maps.maps3d.Map3DElement>();
const cameraStateRef = useTrackedCameraStateRef3D(map3d);
useEffect(() => {
customElements.whenDefined('gmp-map-3d').then(() => {
setCustomElementReady(true);
});
}, []);
// Apply initial options once when the element is first available
useEffect(
() => {
if (!map3d) return;
const {
center,
heading,
tilt,
range,
roll,
defaultCenter,
defaultHeading,
defaultTilt,
defaultRange,
defaultRoll,
// Non-element props to exclude
id,
style,
className,
children,
onCenterChanged,
onHeadingChanged,
onTiltChanged,
onRangeChanged,
onRollChanged,
onCameraChanged,
onClick,
onSteadyChange,
onAnimationEnd,
onError,
mode,
gestureHandling,
...elementOptions
} = props;
const initialCenter = center ?? defaultCenter;
const initialHeading = heading ?? defaultHeading;
const initialTilt = tilt ?? defaultTilt;
const initialRange = range ?? defaultRange;
const initialRoll = roll ?? defaultRoll;
const initialOptions: Partial<google.maps.maps3d.Map3DElementOptions> = {
...elementOptions
};
if (initialCenter) initialOptions.center = initialCenter;
if (initialHeading !== undefined) initialOptions.heading = initialHeading;
if (initialTilt !== undefined) initialOptions.tilt = initialTilt;
if (initialRange !== undefined) initialOptions.range = initialRange;
if (initialRoll !== undefined) initialOptions.roll = initialRoll;
Object.assign(map3d, initialOptions);
},
// this effect should only run when the map3d element first becomes
// available, so we skip re-running it when other props change.
// eslint-disable-next-line react-hooks/exhaustive-deps
[map3d]
);
const isReady = !!maps3dLib && customElementReady;
return [map3d, containerRef, map3dRef, cameraStateRef, isReady] as const;
}