Skip to content

fix(joint-react): StrictMode duplicate feature registration and resetCells ghost cells under React 18#3420

Merged
kumilingus merged 2 commits into
clientIO:masterfrom
samuelgja:fix/joint-react-bugs
Jul 7, 2026
Merged

fix(joint-react): StrictMode duplicate feature registration and resetCells ghost cells under React 18#3420
kumilingus merged 2 commits into
clientIO:masterfrom
samuelgja:fix/joint-react-bugs

Conversation

@samuelgja

@samuelgja samuelgja commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

The library supports React 18+, but development and CI ran only on React 19, which hid two React 18 bugs. This PR fixes both and adds a React 18 test run so they stay fixed.

Fixes

Duplicate paper feature under React 18 StrictMode (selection "2x drag" bug).
useCreateFeature registers paper-target features synchronously during render. React 18's StrictMode invokes the render body twice, and ref writes from the discarded first pass are not carried into the second — so featureRef.current alone could not dedupe, and a second feature instance was constructed. The duplicate's constructor bound paper listeners that were never cleaned up (only the committed instance's clean() runs), so every interaction fired twice — e.g. a selection drag translated each cell by 2x. The hook now adopts an instance already registered in the store (external state, which StrictMode does preserve) instead of constructing a duplicate.

Ghost cells after resetCells().
graph.resetCells() emits a bulk reset containing only adds for the surviving cells — no per-cell remove events. The reactive container therefore kept cells the reset had dropped, and useCells() reported ghost cells the canvas no longer showed. graph-changes now flags reset batches (isReset), and graph-projection prunes any container cell not present in the reset's surviving set, mirroring the reconciliation the React-driven updateGraph() path already does.

Testing

  • New jest.react18.config.mjs runs the full suite with React resolved to an aliased React 18 install (react18 / react18-dom dev deps); the React-19-specific react-compiler project is skipped.
  • yarn test now runs both test:react19 (default) and test:react18.
  • Regression tests: a StrictMode listener-leak test for the feature duplication (passes trivially on React 19, bites on 18) and use-reset-cells-ghost.test.tsx covering both the useCells count and the projection container after resetCells.

@samuelgja
samuelgja requested a review from kumilingus July 7, 2026 16:18
@kumilingus
kumilingus merged commit 0a670d2 into clientIO:master Jul 7, 2026
3 checks passed
@kumilingus kumilingus changed the title fix(joint-react): enhance testing and feature registration for React 18 compatibility fix(joint-react): StrictMode duplicate feature registration and resetCells ghost cells under React 18 Jul 7, 2026
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.

2 participants