From 3e5437fb14019ad6b95ce112a701b1eb1cf7d12c Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 15 Dec 2025 14:42:32 -0500 Subject: [PATCH] Fix stale closure in location update callback + add debug logging --- src/app/room/[slug]/page.tsx | 30 +++++++++++++++++++++++------- src/components/map/MapView.tsx | 5 +++++ src/lib/sync.ts | 4 ++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/app/room/[slug]/page.tsx b/src/app/room/[slug]/page.tsx index 7142ab5..565f757 100644 --- a/src/app/room/[slug]/page.tsx +++ b/src/app/room/[slug]/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useState } from 'react'; +import { useEffect, useState, useRef, useCallback } from 'react'; import { useParams, useRouter } from 'next/navigation'; import dynamic from 'next/dynamic'; import { useRoom } from '@/hooks/useRoom'; @@ -8,7 +8,7 @@ import { useLocationSharing } from '@/hooks/useLocationSharing'; import ParticipantList from '@/components/room/ParticipantList'; import RoomHeader from '@/components/room/RoomHeader'; import ShareModal from '@/components/room/ShareModal'; -import type { Participant } from '@/types'; +import type { Participant, ParticipantLocation } from '@/types'; // Dynamic import for map to avoid SSR issues with MapLibre const DualMapView = dynamic(() => import('@/components/map/DualMapView'), { @@ -61,6 +61,26 @@ export default function RoomPage() { userEmoji: currentUser?.emoji || '👤', }); + // Use refs to avoid stale closures in callbacks + const isConnectedRef = useRef(isConnected); + const updateLocationRef = useRef(updateLocation); + + useEffect(() => { + isConnectedRef.current = isConnected; + }, [isConnected]); + + useEffect(() => { + updateLocationRef.current = updateLocation; + }, [updateLocation]); + + // Stable callback that always uses latest refs + const handleLocationUpdate = useCallback((location: ParticipantLocation) => { + console.log('Location update received:', location.latitude, location.longitude, 'connected:', isConnectedRef.current); + if (isConnectedRef.current) { + updateLocationRef.current(location); + } + }, []); + // Location sharing hook const { isSharing, @@ -68,11 +88,7 @@ export default function RoomPage() { startSharing, stopSharing, } = useLocationSharing({ - onLocationUpdate: (location) => { - if (isConnected) { - updateLocation(location); - } - }, + onLocationUpdate: handleLocationUpdate, updateInterval: 5000, highAccuracy: true, }); diff --git a/src/components/map/MapView.tsx b/src/components/map/MapView.tsx index a250399..a91976b 100644 --- a/src/components/map/MapView.tsx +++ b/src/components/map/MapView.tsx @@ -101,6 +101,11 @@ export default function MapView({ useEffect(() => { if (!map.current || !mapLoaded) return; + console.log('MapView: Updating markers for', participants.length, 'participants'); + participants.forEach((p) => { + console.log(' -', p.name, p.id, 'location:', p.location ? `${p.location.latitude}, ${p.location.longitude}` : 'none'); + }); + const currentMarkers = markersRef.current; const participantIds = new Set(participants.map((p) => p.id)); diff --git a/src/lib/sync.ts b/src/lib/sync.ts index e6b1c6b..fe78927 100644 --- a/src/lib/sync.ts +++ b/src/lib/sync.ts @@ -269,11 +269,15 @@ export class RoomSync { } updateLocation(location: LocationState): void { + console.log('RoomSync.updateLocation called:', location.latitude, location.longitude); if (this.state.participants[this.participantId]) { this.state.participants[this.participantId].location = location; this.state.participants[this.participantId].lastSeen = new Date().toISOString(); this.send({ type: 'location', participantId: this.participantId, location }); + console.log('Location set for participant:', this.participantId, 'Total participants:', Object.keys(this.state.participants).length); this.notifyStateChange(); + } else { + console.warn('Cannot update location - participant not found:', this.participantId); } }