-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Bug description
In PopoverTarget (packages/core/src/components/popover-next/popoverTarget.tsx), mergeRefs is called unconditionally in the render body of a functional component:
const ref = mergeRefs(floatingData.refs.setReference, targetRef);This produces a new ref callback on every render. When React sees a changed ref callback, it invokes the previous one with null and the new one with the DOM node. The setReference(null) triggers a floating-ui state update, which causes a re-render, which creates another new mergeRefs result — producing an infinite loop that crashes with:
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
Notably, Blueprint's own JSDoc on mergeRefs already warns about this:
/**
* Utility for merging refs into one singular callback ref.
* If using in a functional component, would recomend using `useMemo` to preserve function identity.
*/
export function mergeRefs<T>(...refs: Array<React.Ref<T> | undefined>): React.RefCallback<T> {PopoverTarget is a forwardRef functional component but does not follow this guidance.
Steps to reproduce
- Render a
PopoverNextwhose parent re-renders frequently (e.g. connected to a Redux store or React Query cache that resolves synchronously on mount) - The page crashes immediately with a stack trace through
floating-ui.react.mjs→ floating-uisetReference→PopoverTarget
The crash is timing-dependent — it requires the parent to re-render fast enough that React's ref cleanup/re-assignment cycle doesn't settle. Synchronous cache hits (React Query, Redux selectors) reliably trigger it.
Suggested fix
Memoize the mergeRefs call in popoverTarget.tsx:
const ref = useMemo(() => mergeRefs(floatingData.refs.setReference, targetRef), [floatingData.refs.setReference, targetRef]);Environment
@blueprintjs/core6.9.1 (also confirmed ondevelopbranch HEAD)- React 18.3.0
@floating-ui/react(as bundled/re-exported by Blueprint)