Skip to content

installHook.js:1 Error: Maximum update depth exceeded - React 19 + Radix #3799

@mmswi

Description

@mmswi

Bug report

Current Behavior

When using Radix components with React 19, an infinite loop occurs causing the error:

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of
nested updates to prevent infinite loops.
at setRef (composeRefs.tsx:11:5)
at composeRefs.tsx:22:45
at Array.forEach ()
at composeRefs.tsx:22:28
at setRef (composeRefs.tsx:11:5)
at composeRefs.tsx:22:45
...

The setRef function in @radix-ui/react-compose-refs recursively triggers itself, causing React to hit the maximum update depth limit.

In React 19, ref callback behavior changed - ref callbacks can now return cleanup functions, and React may call ref callbacks differently than in React 18. When setRef calls
ref(value) at line 11, it triggers a re-render which invokes setRef again via the composed ref callback at line 22, creating an infinite loop.

Expected behavior

Composed refs should work without causing infinite update loops in React 19.

Reproducible example

I have platejs plugins with radix popovers and radix tooltips on them. If I write fast inside plate, the page breaks.
I'm on a Macbook M1 Pro with 32 GB. One way to trigger this error is to inspect chrome and start a performance recording and start typing real fast. On Safari, for example, it doesn't break. I tried on restarted browser, guest mode. I'm not the only one

CodeSandbox Template

Suggested solution

The composeRefs and useComposedRefs functions need to handle React 19's new ref callback behavior. Possible approaches:

  1. Memoize the composed ref callback to prevent unnecessary re-invocations
  2. Add a guard to prevent recursive setRef calls
  3. Handle the cleanup function return value from React 19 ref callbacks

Additional context

Right now, it works fine with react 18 (even on next.js 16+) and we had to downgrade.

I also saw this reddit post https://www.reddit.com/r/react/comments/1nnvwsp/react_19_causes_maximum_update_depth_exceeded/ where a user raised a similar case

React 19 introduced changes to ref callback behavior, including support for cleanup functions returned from ref callbacks. This may be causing the ref to be re-invoked on each render cycle.

Related stack trace also shows Slate editor involvement:
at Slate.useCallback[onContextChange] (slate.tsx:62:7)
at e.onChange (with-dom.ts:371:7)
at with-react.ts:54:7

This suggests the issue manifests when Radix components are used alongside Slate/Plate editors, where both libraries compose refs.

Your environment

Software Name(s) Version
Radix Package(s) @radix-ui/react-compose-refs 1.1.0
Radix Package(s) @radix-ui/react-accordion 1.2.12
Radix Package(s) @radix-ui/react-avatar 1.1.11
Radix Package(s) @radix-ui/react-checkbox 1.3.3
Radix Package(s) @radix-ui/react-collapsible 1.1.12
Radix Package(s) @radix-ui/react-dialog 1.1.15
Radix Package(s) @radix-ui/react-dropdown-menu 2.1.16
Radix Package(s) @radix-ui/react-hover-card 1.1.15
Radix Package(s) @radix-ui/react-icons 1.3.2
Radix Package(s) @radix-ui/react-popover 1.1.15
Radix Package(s) @radix-ui/react-progress 1.1.8
Radix Package(s) @radix-ui/react-select 2.2.6
Radix Package(s) @radix-ui/react-separator 1.1.8
Radix Package(s) @radix-ui/react-toolbar 1.1.11
Radix Package(s) @radix-ui/react-tooltip 1.2.8
React react, @types/react 19.2.3
Browser Chrome Latest
Assistive tech n/a
Node node 24.13.0
npm/yarn/pnpm pnpm 10.26.0
Operating System macOS Darwin 24.6.0
  • Next.js: 16.1.1
  • TypeScript: 5.9.3
  • platejs: 52.0.15

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions