fix: Behebt TypeError: Cannot read properties of null (reading 'contextmenu') mit Redux
- Implementiert `store.subscribe()` in `setupPolylines.js`, um das Kontextmenü-Handling über Redux zu steuern. - Ersetzt `useDispatch()` und `useSelector()` durch `store.dispatch()` und `store.getState()` in einer Nicht-React-Datei. - Fügt eine `forceClose`-Action in `polylineContextMenuSlice.js` hinzu, um das Kontextmenü synchron mit `setInterval` zu schließen. - Stellt sicher, dass das Kontextmenü **immer vor Ablauf des 20-Sekunden-Intervalls** geschlossen wird. - Verhindert doppelte Menüinstanzen und sorgt für ein stabiles Verhalten bei wiederholten Interaktionen. ✅ Fix für `TypeError: Cannot read properties of null (reading 'contextmenu')` ✅ **Verhindert Kontextmenü-Fehler beim automatischen Datenupdate** ✅ **Redux-gesteuerte Menüverwaltung für stabilere Performance** ✅ **Kein unerwartetes Offenbleiben oder erneutes Rendern des Menüs mehr**
This commit is contained in:
@@ -79,10 +79,15 @@ import ShowAddStationPopup from "../AddPOIModal.js";
|
|||||||
import { useInitGisStationsStatic } from "../mainComponent/hooks/useInitGisStationsStatic";
|
import { useInitGisStationsStatic } from "../mainComponent/hooks/useInitGisStationsStatic";
|
||||||
import { closeAddPoiModal } from "../../redux/slices/addPoiOnPolylineSlice.js";
|
import { closeAddPoiModal } from "../../redux/slices/addPoiOnPolylineSlice.js";
|
||||||
import AddPOIOnPolyline from "../AddPOIOnPolyline";
|
import AddPOIOnPolyline from "../AddPOIOnPolyline";
|
||||||
|
import { closePolylineContextMenu } from "../../redux/slices/polylineContextMenuSlice";
|
||||||
|
import { forceCloseContextMenu } from "../../redux/slices/polylineContextMenuSlice";
|
||||||
|
|
||||||
const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const isPolylineContextMenuOpen = useSelector((state) => state.polylineContextMenu.isOpen);
|
||||||
|
const contextMenuState = useSelector((state) => state.polylineContextMenu);
|
||||||
|
|
||||||
|
const polylinePosition = contextMenuState.position ? L.latLng(contextMenuState.position.lat, contextMenuState.position.lng) : null;
|
||||||
const currentPoi = useSelector(selectCurrentPoi);
|
const currentPoi = useSelector(selectCurrentPoi);
|
||||||
//const setCurrentPoi = useSetRecoilState(currentPoiState);
|
//const setCurrentPoi = useSetRecoilState(currentPoiState);
|
||||||
const polylineVisible = useSelector(selectPolylineVisible);
|
const polylineVisible = useSelector(selectPolylineVisible);
|
||||||
@@ -876,6 +881,13 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
|||||||
console.log("🔥 Automatischer Klick-Event ausgelöst, um Spiderfy zu aktualisieren.");
|
console.log("🔥 Automatischer Klick-Event ausgelöst, um Spiderfy zu aktualisieren.");
|
||||||
map.fire("click");
|
map.fire("click");
|
||||||
}
|
}
|
||||||
|
if (isPolylineContextMenuOpen) {
|
||||||
|
dispatch(closePolylineContextMenu()); // Schließe das Kontextmenü, bevor das nächste Update passiert
|
||||||
|
}
|
||||||
|
if (map) {
|
||||||
|
console.log("🔥 nochmal klick.");
|
||||||
|
map.fire("click");
|
||||||
|
}
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
// Aufräumen bei Komponentenentladung
|
// Aufräumen bei Komponentenentladung
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// /config/appVersion
|
// /config/appVersion
|
||||||
export const APP_VERSION = "1.1.41";
|
export const APP_VERSION = "1.1.42";
|
||||||
|
|||||||
32
redux/slices/polylineContextMenuSlice.js
Normal file
32
redux/slices/polylineContextMenuSlice.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// redux/slices/polylineContextMenuSlice.js
|
||||||
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
isOpen: false,
|
||||||
|
position: null, // Serialisierbarer Wert { lat, lng }
|
||||||
|
forceClose: false, // Neuer State, um das Schließen zu erzwingen
|
||||||
|
};
|
||||||
|
|
||||||
|
const polylineContextMenuSlice = createSlice({
|
||||||
|
name: "polylineContextMenu",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
openPolylineContextMenu: (state, action) => {
|
||||||
|
state.isOpen = true;
|
||||||
|
state.position = { lat: action.payload.position.lat, lng: action.payload.position.lng };
|
||||||
|
state.forceClose = false; // Beim Öffnen zurücksetzen
|
||||||
|
},
|
||||||
|
closePolylineContextMenu: (state) => {
|
||||||
|
state.isOpen = false;
|
||||||
|
state.position = null;
|
||||||
|
},
|
||||||
|
forceCloseContextMenu: (state) => {
|
||||||
|
state.isOpen = false;
|
||||||
|
state.position = null;
|
||||||
|
state.forceClose = true; // Setzt Flagge, um Schließen zu signalisieren
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { openPolylineContextMenu, closePolylineContextMenu, forceCloseContextMenu } = polylineContextMenuSlice.actions;
|
||||||
|
export default polylineContextMenuSlice.reducer;
|
||||||
@@ -11,6 +11,7 @@ import gisSystemStaticReducer from "./slices/webService/gisSystemStaticSlice";
|
|||||||
import gisStationsStaticReducer from "./slices/webService/gisStationsStaticSlice";
|
import gisStationsStaticReducer from "./slices/webService/gisStationsStaticSlice";
|
||||||
import poiTypesReducer from "./slices/db/poiTypesSlice";
|
import poiTypesReducer from "./slices/db/poiTypesSlice";
|
||||||
import addPoiOnPolylineReducer from "./slices/addPoiOnPolylineSlice";
|
import addPoiOnPolylineReducer from "./slices/addPoiOnPolylineSlice";
|
||||||
|
import polylineContextMenuReducer from "./slices/polylineContextMenuSlice";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
@@ -25,5 +26,6 @@ export const store = configureStore({
|
|||||||
gisStationsStatic: gisStationsStaticReducer,
|
gisStationsStatic: gisStationsStaticReducer,
|
||||||
poiTypes: poiTypesReducer,
|
poiTypes: poiTypesReducer,
|
||||||
addPoiOnPolyline: addPoiOnPolylineReducer,
|
addPoiOnPolyline: addPoiOnPolylineReducer,
|
||||||
|
polylineContextMenu: polylineContextMenuReducer,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { polylineLayerVisibleState } from "../redux/slices/polylineLayerVisibleS
|
|||||||
import { useRecoilValue } from "recoil";
|
import { useRecoilValue } from "recoil";
|
||||||
import { store } from "../redux/store"; // Importiere den Store
|
import { store } from "../redux/store"; // Importiere den Store
|
||||||
import { openAddPoiOnPolylineModal } from "../redux/slices/addPoiOnPolylineSlice";
|
import { openAddPoiOnPolylineModal } from "../redux/slices/addPoiOnPolylineSlice";
|
||||||
|
import { openPolylineContextMenu, closePolylineContextMenu } from "../redux/slices/polylineContextMenuSlice";
|
||||||
|
|
||||||
// Funktion zum Deaktivieren der Polyline-Ereignisse
|
// Funktion zum Deaktivieren der Polyline-Ereignisse
|
||||||
export function disablePolylineEvents(polylines) {
|
export function disablePolylineEvents(polylines) {
|
||||||
@@ -51,39 +52,60 @@ export function enablePolylineEvents(polylines, lineColors) {
|
|||||||
// Funktion zum Schließen des Kontextmenüs und Entfernen der Markierung
|
// Funktion zum Schließen des Kontextmenüs und Entfernen der Markierung
|
||||||
function closePolylineSelectionAndContextMenu(map) {
|
function closePolylineSelectionAndContextMenu(map) {
|
||||||
try {
|
try {
|
||||||
// Entferne alle markierten Polylinien
|
// Falls eine Polyline aktiv ist, entfernen
|
||||||
if (window.selectedPolyline) {
|
if (window.selectedPolyline) {
|
||||||
window.selectedPolyline.setStyle({ weight: 3 }); // Originalstil wiederherstellen
|
window.selectedPolyline.setStyle({ weight: 3 });
|
||||||
window.selectedPolyline = null;
|
window.selectedPolyline = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Überprüfe, ob map und map.contextmenu definiert sind
|
// Überprüfen, ob das Kontextmenü existiert, bevor es geschlossen wird
|
||||||
if (map && map.contextmenu) {
|
if (map && map.contextmenu && typeof map.contextmenu.hide === "function") {
|
||||||
map.contextmenu.hide(); // Kontextmenü schließen
|
map.contextmenu.hide(); // Menü schließen
|
||||||
} else {
|
} else {
|
||||||
console.warn("Kontextmenü ist nicht verfügbar.");
|
console.warn("Kontextmenü existiert nicht mehr oder wurde bereits entfernt.");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Fehler beim Schließen des Kontextmenüs:", error);
|
console.error("Fehler beim Schließen des Kontextmenüs:", error);
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Countdown-Status zurücksetzen
|
// Lokale Speicherwerte zurücksetzen
|
||||||
localStorage.removeItem("contextMenuCountdown");
|
localStorage.removeItem("contextMenuCountdown");
|
||||||
localStorage.removeItem("contextMenuExpired");
|
localStorage.removeItem("contextMenuExpired");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Überprüft regelmäßig den Status in localStorage
|
// Überprüft regelmäßig den Status in localStorage
|
||||||
function monitorContextMenu(map) {
|
function monitorContextMenu(map) {
|
||||||
setInterval(() => {
|
function checkAndClose() {
|
||||||
const isContextMenuExpired = localStorage.getItem("contextMenuExpired") === "true";
|
const isContextMenuExpired = localStorage.getItem("contextMenuExpired") === "true";
|
||||||
if (isContextMenuExpired) {
|
|
||||||
closePolylineSelectionAndContextMenu(map);
|
|
||||||
localStorage.removeItem("contextMenuExpired"); // Flagge entfernen, um wiederverwendbar zu sein
|
|
||||||
}
|
|
||||||
}, 1000); // Alle 1 Sekunde überprüfen
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (isContextMenuExpired) {
|
||||||
|
if (map && map.contextmenu && typeof map.contextmenu.hide === "function") {
|
||||||
|
closePolylineSelectionAndContextMenu(map);
|
||||||
|
localStorage.removeItem("contextMenuExpired");
|
||||||
|
} else {
|
||||||
|
console.warn("Kontextmenü war nicht verfügbar und konnte nicht geschlossen werden.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(checkAndClose, 1000); // **Recursive Timeout statt Intervall**
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAndClose();
|
||||||
|
}
|
||||||
|
//------------------------------------------
|
||||||
|
store.subscribe(() => {
|
||||||
|
const state = store.getState(); // Redux-Toolkit empfohlene Methode
|
||||||
|
if (state.polylineContextMenu.forceClose) {
|
||||||
|
console.log("🚀 Redux-Event erkannt - Kontextmenü wird geschlossen.");
|
||||||
|
store.dispatch(closePolylineContextMenu());
|
||||||
|
|
||||||
|
if (window.map && window.map.contextmenu) {
|
||||||
|
window.map.contextmenu.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//--------------------------------------------
|
||||||
export const setupPolylines = (map, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, currentZoom, currentCenter, polylineVisible) => {
|
export const setupPolylines = (map, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, currentZoom, currentCenter, polylineVisible) => {
|
||||||
if (!polylineVisible) {
|
if (!polylineVisible) {
|
||||||
console.warn("Polylines deaktiviert - keine Zeichnung");
|
console.warn("Polylines deaktiviert - keine Zeichnung");
|
||||||
@@ -292,7 +314,7 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
|
|||||||
store.dispatch(openAddPoiOnPolylineModal(e.latlng));
|
store.dispatch(openAddPoiOnPolylineModal(e.latlng));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
text: "Stützpunkt hinzufügen",
|
text: "Stützpunkt hinzufügen",
|
||||||
icon: "/img/icons/gisLines/add-support-point.svg",
|
icon: "/img/icons/gisLines/add-support-point.svg",
|
||||||
@@ -404,15 +426,32 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
|
|||||||
localStorage.setItem("polylineLink", link);
|
localStorage.setItem("polylineLink", link);
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
// Starte den Timer zum Schließen des Kontextmenüs nach 15 Sekunden
|
|
||||||
polyline.on("contextmenu", function (e) {
|
|
||||||
const contextMenu = this._map.contextmenu; // Zugriff auf das Kontextmenü
|
|
||||||
const closeMenu = () => contextMenu.hide(); // Funktion zum Schließen des Menüs
|
|
||||||
|
|
||||||
const countdown = parseInt(localStorage.getItem("contextMenuCountdown"), 30);
|
// Event-Listener für Redux Store-Änderungen registrieren
|
||||||
if (countdown >= 28) {
|
|
||||||
closeMenu();
|
// Starte den Timer zum Schließen des Kontextmenüs nach 15 Sekunden
|
||||||
}
|
|
||||||
|
polyline.on("contextmenu", (e) => {
|
||||||
|
store.dispatch(closePolylineContextMenu());
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!map || !map.contextmenu) return;
|
||||||
|
|
||||||
|
store.dispatch(
|
||||||
|
openPolylineContextMenu({
|
||||||
|
position: { lat: e.latlng.lat, lng: e.latlng.lng },
|
||||||
|
polylineId: polyline.options.idLD,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Schließen nach 17 Sekunden
|
||||||
|
setTimeout(() => {
|
||||||
|
store.dispatch(closePolylineContextMenu());
|
||||||
|
if (map.contextmenu) {
|
||||||
|
map.contextmenu.hide();
|
||||||
|
}
|
||||||
|
}, 17000);
|
||||||
|
}, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
polylines.push(polyline);
|
polylines.push(polyline);
|
||||||
|
|||||||
Reference in New Issue
Block a user