todos-contra-el-fuego-web/imports/ui/components/Maps/MapBridge.js
vjrj e5f7a0f4be fix(maps): entregar el mapa solo cuando tiene tamano real (MapReady)
MapReady entregaba el mapa en el useEffect de montaje, cuando el contenedor
puede no tener tamano todavia. En FiresMap eso hacia que getBounds() lanzara;
el catch solo avisaba ("Failed to set map bounds and scale") y mapSize nunca
se seteaba, con lo que la suscripcion de fuegos por viewport NI SE CREABA:
loading eterno y tile-pane vacio (0 capas) pese a haber 7470 fuegos.

Evidencia: en Meteor.connection._subscriptions solo aparecian activefirestotal,
activefiresuniontotal, settings y userData — ninguna por localizacion.

Ahora se entrega via map.whenReady() + invalidateSize(), solo cuando getSize()
no es 0, con reintento en el evento resize y entrega unica (flag delivered).

Toca el componente compartido por todos los mapas: al desplegar hay que
re-verificar /fires, /zones, /subscriptions, home y detalle de fuego.
SIN DESPLEGAR todavia (la imagen viva es la de 01:33, sin este cambio).
2026-07-28 07:46:19 +02:00

42 lines
1.6 KiB
JavaScript

import { useEffect } from 'react';
import { useMap, useMapEvents } from 'react-leaflet';
// v4 replaces the v1 `ref`/`.leafletElement` + handleLeafletLoad pattern: this
// child runs inside <MapContainer> and hands the ready Leaflet map to a class
// parent once, so the parent can drive it imperatively (setView, fitBounds,
// graphicScale, subsUnion, …).
export const MapReady = ({ onReady }) => {
const map = useMap();
useEffect(() => {
if (!onReady) return undefined;
let cancelled = false;
let delivered = false;
// El efecto de montaje puede correr antes de que el contenedor tenga tamaño.
// Si entregamos el mapa entonces, un `getBounds()` del padre lanza y se queda
// sin bounds: en /fires eso dejaba la suscripcion por viewport sin crear y el
// mapa vacio (0 capas) pese a haber 7470 fuegos. Esperamos a que el mapa este
// listo Y tenga tamaño real; entregamos una sola vez.
const deliver = () => {
if (cancelled || delivered) return;
map.invalidateSize();
const size = map.getSize();
if (!size || size.x === 0 || size.y === 0) return;
delivered = true;
onReady(map);
};
map.whenReady(deliver);
map.on('resize', deliver);
return () => {
cancelled = true;
map.off('resize', deliver);
};
}, [map]); // eslint-disable-line react-hooks/exhaustive-deps
return null;
};
// Bridges Leaflet map events to callbacks (replaces the v1 onMoveend /
// onViewportChanged / onZoomend props on <Map>).
export const MapEvents = ({ handlers }) => {
useMapEvents(handlers || {});
return null;
};