Skip to content

fix: re-initialize CldVideoPlayer after unmount and remount - #669

Merged
PaulBoye-py merged 1 commit into
betafrom
fix/video-player-remount
Oct 12, 2026
Merged

PaulBoye-py merged 1 commit into
betafrom
fix/video-player-remount

Conversation

@PaulBoye-py

Copy link
Copy Markdown
Collaborator

Description

CldVideoPlayer doesn't come back after it's unmounted and mounted again (for example after navigating away and back, or toggling it in the tree). The <video> element returns, but the Cloudinary player never re-attaches, so no controls and no poster. This is the remaining part of #572, which #602 attempted to fix.

Root cause (two parts):

  1. The player was never fully disposed on unmount: The cleanup called videojs.cloudinary.dispose(), which only disposes the Cloudinary plugin, so the player stayed registered with video.js.
    • With an id prop, remounting found that stale player under the same id, and the new <video> element was never initialized.
    • Without an id, a new id is generated on each mount, so it appeared to work, but every remount left another live player behind.
  2. No initialization on remount with the same script id: Next.js <Script> doesn't fire onLoad again for a script id it has already loaded, so the player setup never ran.

Changes (one file):

  • Dispose the player with its own dispose() on unmount, which also removes it from the video.js registry. This is skipped when the player's <video> element is still in the page, which is the case during React Strict Mode's simulated unmount (the same element is reused and dispose() would remove it).
  • Add onReady alongside onLoad on the player script. onReady also runs on later mounts once the script is loaded.
  • Guard initialization with the player ref instead of the playerInitialized state, since onLoad and onReady can both run during the same render and the state value there may be stale.

The upload widget isn't affected: I checked that CldUploadWidget still opens after a remount.

Issue Ticket Number

Related to #572. Flagged during the v7.0.0 planning in #523.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Fix or improve the documentation
  • This change requires a documentation update

Checklist

  • I have followed the contributing guidelines of this project as mentioned in CONTRIBUTING.md
  • I have created an issue ticket for this PR
  • I have checked to ensure there aren't other open Pull Requests for the same update/change?
  • I have performed a self-review of my own code
  • I have run tests locally to ensure they all pass
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes needed to the documentation

Testing

Tested in the Next.js 16 test app with a page that removes and re-adds the player, in both a production build and dev mode (React Strict Mode), with and without an id prop, over 4 mount cycles:

Before After
With id Player gone after the first remount Player, controls and poster return every time; it plays
Without id Worked, but one extra live player per remount Works, with exactly one live player
  • First mount still works in all 14 CldVideoPlayer scenarios from my feat: upgrade Cloudinary video player from v1 to v4 #665 testing (one player each, no duplicates in Strict Mode, no page errors).
  • onPlay and onPause still fire once.
  • Unit tests pass (16/16), and the library builds and typechecks.

The player was never fully disposed on unmount (only the Cloudinary
plugin was), so it stayed registered with video.js. With an `id` prop,
remounting reused that stale player and the new <video> element was
never initialized; without one, every remount leaked a player. Next.js
also doesn't fire onLoad again for a script id it already loaded.

Dispose the player on unmount (skipping React Strict Mode's simulated
unmount, which reuses the same element), add onReady alongside onLoad
so remounts initialize again, and guard initialization with the player
ref instead of possibly stale state.
@vercel

vercel Bot commented Oct 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
next-cloudinary Ready Ready Preview Oct 6, 2026 1:42pm UTC

Request Review

@PaulBoye-py
PaulBoye-py merged commit 6f738f4 into beta Oct 12, 2026
7 checks passed
@PaulBoye-py
PaulBoye-py deleted the fix/video-player-remount branch October 12, 2026 20:06

This branch was successfully deployed

1 active deployment
Preview — 4b37a24e Deployed Oct 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant