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 invariant from 'tiny-invariant';
|
||||||
|
|
||||||
import { useStyle } from './hooks';
|
import { useStyle, useElementVisible } from './hooks';
|
||||||
import { StyleControl } from './StyleControl';
|
import { StyleControl } from './StyleControl';
|
||||||
|
|
||||||
const Context = createContext<{ map?: Map | null }>({});
|
const Context = createContext<{ map?: Map | null }>({});
|
||||||
|
@ -35,6 +35,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const visible = useElementVisible(containerRef);
|
||||||
const [map, setMap] = useState<Map | null>();
|
const [map, setMap] = useState<Map | null>();
|
||||||
|
|
||||||
const onStyleChange = useCallback(
|
const onStyleChange = useCallback(
|
||||||
|
@ -48,7 +49,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
||||||
const { style, ...mapStyleProps } = useStyle(layers, onStyleChange);
|
const { style, ...mapStyleProps } = useStyle(layers, onStyleChange);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSupported && !map) {
|
if (isSupported && visible && !map) {
|
||||||
invariant(containerRef.current, 'Map container not found');
|
invariant(containerRef.current, 'Map container not found');
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
container: containerRef.current,
|
container: containerRef.current,
|
||||||
|
@ -59,7 +60,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
||||||
setMap(map);
|
setMap(map);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [map, style, isSupported]);
|
}, [map, style, visible, isSupported]);
|
||||||
|
|
||||||
if (!isSupported) {
|
if (!isSupported) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import { useCallback, useEffect, useState, useMemo } from 'react';
|
import {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
useMemo,
|
||||||
|
type RefObject
|
||||||
|
} from 'react';
|
||||||
import type {
|
import type {
|
||||||
LngLatBoundsLike,
|
LngLatBoundsLike,
|
||||||
LngLat,
|
LngLat,
|
||||||
|
@ -118,3 +124,30 @@ export function useStyle(
|
||||||
|
|
||||||
return { style, layers, setStyle, setLayerEnabled, setLayerOpacity };
|
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