Merge pull request #9442 from tchak/fix-conditional-map-display
fix(carte): initialize map only when container is visible
This commit is contained in:
commit
1ba28cc8d3
2 changed files with 38 additions and 4 deletions
|
@ -13,7 +13,7 @@ import type { Style } from 'maplibre-gl';
|
|||
|
||||
import invariant from 'tiny-invariant';
|
||||
|
||||
import { useStyle } from './hooks';
|
||||
import { useStyle, useElementVisible } from './hooks';
|
||||
import { StyleControl } from './StyleControl';
|
||||
|
||||
const Context = createContext<{ map?: Map | null }>({});
|
||||
|
@ -35,6 +35,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
|||
[]
|
||||
);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const visible = useElementVisible(containerRef);
|
||||
const [map, setMap] = useState<Map | null>();
|
||||
|
||||
const onStyleChange = useCallback(
|
||||
|
@ -48,7 +49,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
|||
const { style, ...mapStyleProps } = useStyle(layers, onStyleChange);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSupported && !map) {
|
||||
if (isSupported && visible && !map) {
|
||||
invariant(containerRef.current, 'Map container not found');
|
||||
const map = new Map({
|
||||
container: containerRef.current,
|
||||
|
@ -59,7 +60,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
|||
setMap(map);
|
||||
});
|
||||
}
|
||||
}, [map, style, isSupported]);
|
||||
}, [map, style, visible, isSupported]);
|
||||
|
||||
if (!isSupported) {
|
||||
return (
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
useMemo,
|
||||
type RefObject
|
||||
} from 'react';
|
||||
import type {
|
||||
LngLatBoundsLike,
|
||||
LngLat,
|
||||
|
@ -118,3 +124,30 @@ export function useStyle(
|
|||
|
||||
return { style, layers, setStyle, setLayerEnabled, setLayerOpacity };
|
||||
}
|
||||
|
||||
function isElementVisible(
|
||||
element: HTMLElement,
|
||||
callback: (visible: boolean) => void
|
||||
) {
|
||||
if (element.offsetWidth > 0 && element.offsetHeight > 0) {
|
||||
callback(true);
|
||||
} else {
|
||||
callback(false);
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => callback(entries[0].isIntersecting == true),
|
||||
{ threshold: [0] }
|
||||
);
|
||||
observer.observe(element);
|
||||
return () => observer.unobserve(element);
|
||||
}
|
||||
}
|
||||
|
||||
export function useElementVisible(element: RefObject<HTMLElement>) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
useEffect(() => {
|
||||
if (element.current) {
|
||||
return isElementVisible(element.current, setVisible);
|
||||
}
|
||||
}, [element]);
|
||||
return visible;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue