Skip to content

fix(dockview-core): cancel popout restoration on dispose (#851)#1288

Merged
mathuo merged 1 commit into
masterfrom
fix/851-popout-restoration-disposed-guard
May 16, 2026
Merged

fix(dockview-core): cancel popout restoration on dispose (#851)#1288
mathuo merged 1 commit into
masterfrom
fix/851-popout-restoration-disposed-guard

Conversation

@mathuo
Copy link
Copy Markdown
Owner

@mathuo mathuo commented May 16, 2026

Summary

  • Fixes #851 — duplicate popouts when the page is refreshed under React StrictMode.
  • DockviewComponent.fromJSON schedules popout-group restoration via setTimeout, but the timer callbacks were neither cancelled when the component was disposed nor guarded against isDisposed. Under StrictMode the component mounts -> disposes -> remounts, and the first instance's queued restoration still fired, opening a second popout window with a fresh sequential target name.
  • Now each restoration timer is tracked in a cleanup set on the component, cleared by the main Disposable.from(...) block in dispose(), and the timeout body early-returns when this.isDisposed. Pending promises resolve during cleanup so callers awaiting popoutRestorationPromise don't hang.

Test plan

  • New regression test dockviewComponent › popout group › issue #851: fromJSON popout restoration is cancelled on dispose — schedules a popout via fromJSON, disposes before the timer fires, runs all fake timers, and asserts window.open is never called.
  • Test verified to fail without the production change (Received number of calls: 1) and pass with it.
  • Full popout group suite still green (24 tests).
yarn jest --testPathPatterns dockviewComponent.spec --testNamePattern "issue #851"   # 1 passed
yarn jest --testPathPatterns dockviewComponent.spec --testNamePattern "popout"       # 24 passed

🤖 Generated with Claude Code

`fromJSON` schedules popout-group restoration via `setTimeout`, but the
timer callbacks were not cancelled when the component was disposed and
did not check `isDisposed` before calling `addPopoutGroup`. Under React
StrictMode the component mounts -> disposes -> remounts, and the first
instance's queued restoration still fired against the disposed
component, opening a second popout window with a fresh target name.

Track each restoration timer in a cleanup set, clear it from the
component's main disposable, and early-return from the timeout body if
the component is already disposed. The pending promises are resolved
during cleanup so callers awaiting `popoutRestorationPromise` don't hang.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mathuo mathuo merged commit 7d74ad6 into master May 16, 2026
4 checks passed
@sonarqubecloud
Copy link
Copy Markdown

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.

Duplicate popouts when page is refreshed

1 participant