fix: properly cleanup video event listeners on unmount

- Store cleanup function reference for pending video event listeners
- Call cleanup in onUnmounted to prevent memory leaks if component
  unmounts while waiting for video metadata
This commit is contained in:
Johnpaul
2025-11-27 04:06:19 +01:00
parent 8031a832f4
commit 51ab1541dd

View File

@@ -100,6 +100,8 @@ const originalWidgets = ref<IBaseWidget[]>([])
const videoRef = ref<HTMLVideoElement>() const videoRef = ref<HTMLVideoElement>()
const videoContainerRef = ref<HTMLElement>() const videoContainerRef = ref<HTMLElement>()
const stream = ref<MediaStream | null>(null) const stream = ref<MediaStream | null>(null)
// Track pending video event listeners for cleanup
const pendingVideoCleanup = ref<(() => void) | null>(null)
const isHovered = useElementHover(videoContainerRef) const isHovered = useElementHover(videoContainerRef)
const canvas = document.createElement('canvas') const canvas = document.createElement('canvas')
// Persistent video element for capture - not in DOM template but keeps stream active // Persistent video element for capture - not in DOM template but keeps stream active
@@ -602,22 +604,30 @@ async function startCameraPreview() {
const video = videoRef.value const video = videoRef.value
const onLoadedMetadata = () => { const cleanup = () => {
video.removeEventListener('loadedmetadata', onLoadedMetadata) video.removeEventListener('loadedmetadata', onLoadedMetadata)
video.removeEventListener('error', onError)
pendingVideoCleanup.value = null
}
const onLoadedMetadata = () => {
cleanup()
resolve() resolve()
} }
const onError = (error: Event) => { const onError = (error: Event) => {
video.removeEventListener('error', onError) cleanup()
reject(error) reject(error)
} }
video.addEventListener('loadedmetadata', onLoadedMetadata) video.addEventListener('loadedmetadata', onLoadedMetadata)
video.addEventListener('error', onError) video.addEventListener('error', onError)
// Store cleanup function for onUnmounted
pendingVideoCleanup.value = cleanup
setTimeout(() => { setTimeout(() => {
video.removeEventListener('loadedmetadata', onLoadedMetadata) cleanup()
video.removeEventListener('error', onError)
resolve() resolve()
}, 1000) }, 1000)
}) })
@@ -677,6 +687,8 @@ onMounted(async () => {
}) })
onUnmounted(() => { onUnmounted(() => {
// Clean up any pending video event listeners
pendingVideoCleanup.value?.()
stopStreamTracks() stopStreamTracks()
restoreWidgets() restoreWidgets()
}) })