Skip to content

fix: React 19 clusterer infinite loop (#19) + SSR document crash#22

Open
w3di wants to merge 1 commit into
fede4ka1245:mainfrom
w3di:fix/react-19-clusterer-infinite-loop-and-ssr
Open

fix: React 19 clusterer infinite loop (#19) + SSR document crash#22
w3di wants to merge 1 commit into
fede4ka1245:mainfrom
w3di:fix/react-19-clusterer-infinite-loop-and-ssr

Conversation

@w3di

@w3di w3di commented Jun 15, 2026

Copy link
Copy Markdown

Two issues when using the package with React 19.

1. Infinite re-render loop in YMapCustomClusterer (fixes #19, related to #15)

Rendering <YMapCustomClusterer> under React 19 throws Maximum update depth exceeded and the page hangs.

Root cause: React 19 changed callback-ref semantics — refs are re-invoked null -> value on every render (not only mount/unmount). YMapCustomClusterer forwards ref to the reactified YMapClusterer, so under React 19 the reactified clusterer re-binds on every render and loops through its internal setState (onRender).

Confirmed by several users in #19 on React 19.2.0.

2. document is not defined during SSR

EventBus calls document.appendChild(...) in its constructor, and a module-level mapEventBus is created at import time. On the server (e.g. Next.js prerender) document does not exist, so importing the package throws.

Fix

  • YMapCustomClusterer: forward ref only on React <= 18 (parseInt(React.version, 10) < 19). On React 18 the imperative clusterer handle keeps working exactly as before; on React 19 the ref is skipped to avoid the infinite loop. This keeps backward compatibility and only changes behaviour where it currently crashes.
  • EventBus: create the underlying EventTarget lazily via a getter, so the constructor no longer touches document at import time.

Source-only changes; npm run build (vite build && tsc) passes.

Note

On React 19 the ref (imperative YMapClusterer handle) is not exposed, since forwarding it is exactly what triggers the loop. If you prefer a different approach for exposing the handle on React 19, happy to adjust.

@w3di w3di force-pushed the fix/react-19-clusterer-infinite-loop-and-ssr branch 4 times, most recently from 5e6fc91 to c83589b Compare June 15, 2026 16:05
… crash

- YMapCustomClusterer: stop forwarding `ref` to the reactified clusterer.
  React 19 re-invokes callback refs null->value on every render, and reactify
  composes the forwarded ref into an unstable callback ref, so the clusterer
  re-binds each render and loops with 'Maximum update depth exceeded'. The root
  fix belongs in reactify (CDN); not forwarding the ref is the only lever at the
  package level. Fixes fede4ka1245#19.
- EventBus: create the underlying EventTarget lazily so the constructor does not
  touch `document` at import time. Fixes SSR 'document is not defined'.
@w3di w3di force-pushed the fix/react-19-clusterer-infinite-loop-and-ssr branch from c83589b to 848fda5 Compare June 15, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant