Skip to content

useVideoTexture: cached video element not cleaned up on unmount #2712

@mohamedtahaguelzim

Description

@mohamedtahaguelzim
  • three version: ^0.159.0
  • @react-three/fiber version: ^9.0.0
  • @react-three/drei version: latest (confirmed by reading current master source)
  • node version: N/A (reproducible across versions)
  • npm (or yarn) version: N/A

Problem description:

useVideoTexture uses suspend-react to cache the <video> element creation, keyed by [srcOrSrcObject]. When a component using useVideoTexture unmounts (e.g. by changing a key prop), the cached video element persists and continues playing in the background.

The current cleanup effect only destroys the HLS instance but does not pause or dispose the underlying video element, nor does it evict the suspend-react cache entry:

useEffect(() => {
  start && texture.image.play()

  return () => {
    if (hlsRef.current) {
      hlsRef.current.destroy()
      hlsRef.current = null
    }
    // no video.pause(), no video.src = "", no cache eviction
  }
}, [texture, start])

The VideoTexture component does call texture.dispose() on unmount, but that only disposes the Three.js texture object - the HTML <video> element that suspend-react keeps in its cache remains alive and playing.

Expected behavior: when a component using useVideoTexture unmounts, the underlying <video> element should be paused and cleaned up, and the suspend-react cache entry should be evicted.

Steps to reproduce:

  1. Render a component that uses useVideoTexture with a video source
  2. Switch to a different video by changing a key prop (causing unmount + remount with a new source)
  3. Unmute audio - you can hear both videos playing simultaneously
  4. Switch back - the timestamp of the previous video is preserved (it never stopped)

Relevant code:

Minimal reproduction repo: https://github.com/mohamedtahaguelzim/drei-video-bug

  • Clone, npm install, npm run dev
  • Use the buttons to switch videos and unmute
  • Open the console to observe mount/unmount logs - the cached video persists despite unmounting

Suggested solution:

The cleanup effect in useVideoTexture should:

  1. Pause the video element (video.pause())
  2. Clear the video source (video.removeAttribute('src'); video.load())
  3. Dispose the texture
  4. Evict the suspend-react cache entry using clear() with the matching key ([srcOrSrcObject])

This follows the same cleanup pattern already used by WebcamVideoTexture and ScreenVideoTexture.

Fix submitted in #2714.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions