[React 19] infinite re-render when `setFloating` is paired with `DropdownMenuTrigger` + `useOptimistic`

Author: branxyCreated Nov 27, 2025Updated Mar 5, 2026
LabelsNEEDS: triage

It is an issue involving an external library but it seems serious enough to be considered.

Floating dropdown menu. When setFloating is placed as a ref callback on DropdownMenuTrigger (RadixUI) or it's direct child, a call to setOptimistic inside DropdownMenuItem's onSelect causes an infinite re-render loop.

typescript
<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <button ref={refs.setFloating}>Open dropdown</button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem
      onSelect={() => {
        startTransition(() => {
          setStateOptimistic([]);
         });
      }}
     >
      Call setStateOptimistic()
    </DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

The bug occurs only when both these 2 conditions meet:

  1. A useOptimistic hook is used AND an object is returned from its' updateFn.
    • works fine when useState with objects is used instead of useOptimistic.
    • works fine when primitive values are returned from useOptimistic's updateFn instead of objects.
  2. A setFloating ref setter from useFloating is placed on a DropdownMenuTrigger or it's' direct child when using asChild.
    • merging refs (e.g. via useMergeRefs) doesn't help
    • works fine when setFloating is removed from DropdownMenuTrigger or it's child.
    • works fine when plain HTML element is used instead of Radix's DropdownMenu.

  • I get that it's not a bug per se: RadixUI and useOptimistic are involved, but I would appreciate an advice on whether this behaviour is expected when making floating dropdowns, or how can it be fixed.
  • It's also weird to me that useOptimistic's updateFn just keeps infinitely running even though the setOptimistic call doesn't repeat.
  • So far the only workaround I found is stuffing a dummy div inside the DropdownMenuTrigger — it catches the radix ref, and it seems to fix the issue:
typescript
<DropdownMenuTrigger asChild>
  {/* ↓ catches the radix ref */}
  <div>
    {/* ↓ catches the floating ref */}
    <button ref={refs.setFloating}>Open dropdown</button>     
  </div>
</DropdownMenuTrigger>

Reproduction

React sandbox: https://codesandbox.io/p/devbox/78mrty?migrateFrom=ygxc37

Steps:

  1. Click "Open dropdown".
  2. Click "call setStateOptimistic()".
  3. See error in console.

Expected behavior

No infinite re-renders.

Context: