tldraw/tldraw

TickManager listener lifecycle is the root cause of the strict-mode camera-state workaround

已關閉

#8,892 建立於 2026年5月20日

 (2 則留言) (0 個反應) (1 位負責人)TypeScript (3,212 個分叉)batch import
good first issueimprovementsdksprint

倉庫指標

星標
 (47,037 顆星)
PR 合併指標
 (PR 指標待抓取)

描述

Problem

The "reset camera state on dispose" block in Editor.ts:411–416 papers over a deeper issue: 'tick' event listeners are added by Editor after TickManager starts, but TickManager.dispose doesn't track or remove them — they're owned by the EventEmitter superclass. On React Strict Mode double-mount, listeners may re-bind to stale closure scopes.

Where

  • packages/editor/src/lib/editor/managers/TickManager/TickManager.ts:49–55dispose only cancels RAF, doesn't unregister listeners
  • packages/editor/src/lib/editor/Editor.ts:411–416 — the workaround comment plus off('tick', ...) and _setCameraState('idle') reset
  • Multiple 'tick' listener call sites across Editor.ts

Suggested fix

Let TickManager own the listener registry: onTick(cb) returns an unsubscribe, and TickManager.dispose unregisters all of them. Demote editor.inputs.updatePointerVelocity from a privileged hard-coded call inside tick() to an ordinary frame listener registered by InputsManager. Once that's symmetric, the workaround in Editor.ts:411–416 can be removed.

Context

Surfaced during an internal modularity audit of the editor manager classes.

貢獻者指南