Skip to content

Maximum update depth exceeded error with hover card #2717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
resthedev opened this issue Feb 21, 2024 · 38 comments
Closed

Maximum update depth exceeded error with hover card #2717

resthedev opened this issue Feb 21, 2024 · 38 comments

Comments

@resthedev
Copy link

resthedev commented Feb 21, 2024

Bug report

Current Behavior

image

Been banging my head against the wall with this one, so maybe someone has an idea on how to fix this.

Here is the full error stack trace:

Unhandled Runtime 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.

Call Stack
throwIfInfiniteUpdateLoopDetected
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (26657:10)
throwIfInfiniteUpdateLoopDetected
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (7679:2)
getRootForUpdatedFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (7570:9)
enqueueConcurrentHookUpdate
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (12929:15)
onAnchorChange
node_modules/@radix-ui/react-popper/dist/index.mjs (62:16)
create
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (21035:22)
commitHookEffectListMount
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23088:6)
commitHookPassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23193:10)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23304:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)
commitPassiveMountOnFiber
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23171:6)
recursivelyTraversePassiveMountEffects
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (23190:8)

I am getting this error primarily when I am using the Radix hover card with code that re-renders frequently (in my case, react-query). This can be seen in the minimal reproduction linked later in this post. As react-query's useQuery hook rerenders its parent, it causes the HoverCard to mount and rerender, causing the error. I've tried to memoize the hover card, but this did not fix the issue.

Expected behavior

Error should not occur

Reproducible example

CodeSandbox Reproduction

Steps to reproduce

  1. Open Preview console in the CodeSandbox

CleanShot 2024-02-20 at 23 31 13@2x

  1. Refresh the CodeSandbox window

CleanShot 2024-02-20 at 23 32 08@2x

  1. Note the error in the console

Suggested solution

It seems to be related to the onAnchorChange function call, but i'm not sure precisely how to solve this or where the root problem is (the library or my code).

Additional context

No error is thrown if I only render a few buttons. Seems like React has a built in max limit before it throws an error.
For my use case where I need to render 50-100 items at once with a hover card for each item, this error is a breaking issue.

Your environment

Software Name(s) Version
Radix Package(s) @radix-ui/react-hover-card latest
React n/a latest
Browser Arc latest
Assistive tech
Node n/a latest
npm/yarn latest
Operating System Mac OS Sonoma latest
@benoitgrelard
Copy link
Contributor

I see some other warning:
CleanShot 2024-02-29 at 13 03 32@2x

It's unlikely to be an issue with the primitive, but rather with the specific setup.

I will close the issue now, but feel free to keep chatting if you have more info to present.

@resthedev
Copy link
Author

resthedev commented Mar 2, 2024

I see some other warning: CleanShot 2024-02-29 at 13 03 32@2x

It's unlikely to be an issue with the primitive, but rather with the specific setup.

I will close the issue now, but feel free to keep chatting if you have more info to present.

Hi @benoitgrelard — thanks for responding.
I was going off of the official radix-ui/primitives CodeSandbox template provided when I made this bug report.
I switched to createroot and it seems to stop the error from occurring inside the CodeSandbox.

I am using NextJS in my own application (where I am encountering the issue), which should already be using createRoot. I'm wondering if it's a clue though that something in my setup may be causing the issue. Any other ideas why this may be happening?

@mwaterman29
Copy link

I'm getting this as well in Next - the only useful info to debug is that popper appears in the call stack:
image

I also have a popover that re-renders frequently, and then causes this error. This does seem like an issue with the primitive.

@thefathdev
Copy link

I am also getting this issue when using Popover
image

@wintercounter
Copy link

Same here, for me, it happens when I'm resizing the window.

@shubham-giraft
Copy link

Happened to me on a page where I was using 50+ popovers.

@mwaterman29
Copy link

Something is definitely not right here.
image

I have a common component for navigation buttons with a tooltip. I've got probably 4-6 of these on screen at a time, and occasional re-renders cause this error with a huge depth.

@resthedev
Copy link
Author

Glad I'm not alone. This is not an actual fix but for my own purposes I've just wrapped my component in an error boundary for now so that it doesn't bubble up and crash the entire application.

Hopefully this can be properly fixed though.

@TobxD
Copy link

TobxD commented Aug 14, 2024

I am also experiencing this with many HoverCards that re-render often. Would appreciate any pointers to fix this!

@resthedev
Copy link
Author

@benoitgrelard Would we be able to reopen this issue as it seems like many others are also experiencing the same bug. Thank you!

@gonggqing
Copy link

Got similar issue when using Radix-ui dropdown menu with Next.js. Please take a look at this! @benoitgrelard The console report Maximum update depth exceeded too.

@Randulfe
Copy link

Randulfe commented Nov 2, 2024

Having the same issue with Nextjs + Radix + reactflow when a context menu wraps over the nodes and the nodes start being dragged

@IvanSmiths
Copy link

Did anyone found some workaround? I am getting this error also with the DropdownMenu.Trigger primitive with Next.js each time I do an api call

@ilyabo
Copy link

ilyabo commented Nov 14, 2024

We also experience the issue with shadcn Tooltip in a Next.js app :(

@Randulfe
Copy link

@benoitgrelard any ideas or will this issue be reopened as it seems to be a recurring issue?

@Pipe-Runner
Copy link

I suddenly started getting this error out of no where. The popover worked fine a few months back and now all of a sudden I am getting this.
image

@Szuszi
Copy link

Szuszi commented Dec 17, 2024

Also experiencing this when using Radix Dialog that has a material UI Popover or Select component inside:

image

@Pipe-Runner
Copy link

Also experiencing this when using Radix Dialog that has a material UI Popover or Select component inside:

image

I am actually considering switching to Daisy UI instead of using Shadcn because of this. This is a UI breaking bug. And seems like there is no activity on this.

@gonggqing
Copy link

gonggqing commented Dec 21, 2024

Also experiencing this when using Radix Dialog that has a material UI Popover or Select component inside:

image

I am actually considering switching to Daisy UI instead of using Shadcn because of this. This is a UI breaking bug. And seems like there is no activity on this.

At the first glance I thought it was due to my misuses of useEffect, but after reviewing people's comments, looks like it's not my fault🥲. It takes me a while to end up here ...

@Pipe-Runner
Copy link

Folks, I upgraded my react version to the latest minor version of major version 18. This seems to have been fixed since then. Give it a try.

@c45
Copy link

c45 commented Dec 23, 2024

any updates here? on react 19.0.0 (latest), still happening, so unfortunately no option to upgrade

@Harukisatoh
Copy link

I have the same error using a DropdownMenu.

@IvanSmiths
Copy link

I have the same error using a DropdownMenu.

Are you using React 19? To me worked out downgrading to React 18

@Strernd
Copy link

Strernd commented Jan 16, 2025

I am encountering the same problem when using a few dozen Popovers. @benoitgrelard please consider reopening this issue as this doesn't seems to have something to do with the setup you mentioned.

@vipafutu
Copy link

vipafutu commented Feb 4, 2025

Having the same problem with several popovers as well. Using react 18.3.1 and NextJS 14.

@Randulfe
Copy link

Randulfe commented Feb 4, 2025

@benoitgrelard bunch of others facing the same issue, please reconsider reopening or opening a new one. Should be investigated and should be compatible with React 19

@holoiii
Copy link

holoiii commented Feb 6, 2025

+1 to this, exact same issue

@efitzkiwi
Copy link

This also happens with the Collapsible component, I highly recommend migrating to ark-ui primitives as I've had nothing but problems with radix unfortunately

@Randulfe
Copy link

Ive created this issue to reopen this as so many of us are still experiencing this issue even with the latest versions: #2717

On the meanwhile, has anyone found a workaround?

@Randulfe
Copy link

Yo! This fix on a fork I made solved the issue for me, in case it can help anyone else I opened a PR: #3386

@Harukisatoh
Copy link

Harukisatoh commented Feb 27, 2025

@benoitgrelard Do we still think this is something with his setup? If so, how can we solve it?

@darklight9811
Copy link

darklight9811 commented Mar 4, 2025

I'm having this issue using this code:

import { Check, ChevronsUpDown } from "lucide-react";
import * as React from "react";

import { PopoverTrigger } from "@radix-ui/react-popover";
import { useControllableState } from "@radix-ui/react-use-controllable-state";
import { CommandLoading } from "cmdk";
import { cn } from "../../lib/utils";
import { Button } from "./button";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "./command";
import { Popover, PopoverContent } from "./popover";

interface Props {
	t?: {
		placeholder: string;
		empty: string;
		loading: string;
	};

	value?: string;
	onChange?: (value: string) => void;
	onTextChange?: (text: string) => void;
	loading?: boolean;
	creatable?: boolean;
	prefix?: React.ReactNode;
	className?: string;
	options?: {
		id?: string;
		name?: string;
		value: string;
		label?: React.ReactNode;
	}[];
}

export function Combobox(props: Props) {
	const [open, setOpen] = React.useState(false);
	const [text, settext] = React.useState("");
	const [value, setValue] = useControllableState({
		prop: props.value,
		defaultProp: "",
		onChange: props.onChange,
	});

	const options = React.useMemo(() => {
		return (
			props.options?.map((option) => ({
				value: option.id || option.value || option.label,
				label: option.name || option.label || option.value,
			})) || []
		).concat(text ? [{ value: text, label: text }] : []);
	}, [props.options, text]);

	return (
		<Popover open={open} onOpenChange={setOpen}>
			<PopoverTrigger asChild>
				<Button
					variant="outline"
					aria-expanded={open}
					className={cn("w-full justify-between px-2", props.className)}
					onClick={() => setOpen(!open)}
				>
					<span className="flex gap-2 items-center">
						{props.prefix}
						{value ? (
							options.find((option) => option.value === value)?.label
						) : (
							<span>{props.t?.placeholder || ""}</span>
						)}
					</span>
					<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
				</Button>
			</PopoverTrigger>
			<PopoverContent className="w-full p-0">
				<Command shouldFilter={false}>
					<CommandInput
						placeholder={props.t?.placeholder}
						onValueChange={(value) => {
							if (props.creatable) settext(value);
							props.onTextChange?.(value);
						}}
					/>
					<CommandEmpty>{props.t?.empty}</CommandEmpty>
					{(!props.options || props.loading) && props.t?.loading && (
						<CommandLoading>{props.t.loading}</CommandLoading>
					)}
					<CommandList>
						<CommandGroup>
							{options.map((option) => (
								<CommandItem
									key={option.value as string}
									value={option.value as string}
									className="gap-2 justify-between"
									onSelect={(currentValue) => {
										const select = currentValue === value ? "" : currentValue;
										setValue(select);
										setOpen(false);
									}}
								>
									<div className="flex gap-2 items-center">{option.label}</div>
									<Check
										className={cn("h-4 w-4", value === option.value ? "opacity-100" : "opacity-0")}
									/>
								</CommandItem>
							))}
						</CommandGroup>
					</CommandList>
				</Command>
			</PopoverContent>
		</Popover>
	);
}

the imports are shadcn related, so you can just import its components

@darklight9811
Copy link

this is the error stacktrace from react:

Image

@Randulfe
Copy link

Randulfe commented Mar 4, 2025

Does forking with this fix work for you @darklight9811 ? #3386

@darklight9811
Copy link

darklight9811 commented Mar 5, 2025

@Randulfe sadly not, I dont even have the context-menu package installed, the bug Im encountering is here:

Image

(maybe the effect without a deps array)

@DannyDelott
Copy link

We switched from @radix-ui/tootltip to floating-ui (aka Popper.js) and are still seeing this error. I suspect since radix-ui is using floating-ui under the hood this might be an issue with the underlying library and not necessarily an issue with radix-ui itself.

I'm going to see if I can refactor OP's repro sandbox to demonstrate this using floating UI.

@jarvis394
Copy link

const PopperAnchor = React.forwardRef<PopperAnchorElement, PopperAnchorProps>(
(props: ScopedProps<PopperAnchorProps>, forwardedRef) => {
const { __scopePopper, virtualRef, ...anchorProps } = props;
const context = usePopperContext(ANCHOR_NAME, __scopePopper);
const ref = React.useRef<PopperAnchorElement>(null);
const composedRefs = useComposedRefs(forwardedRef, ref);
React.useEffect(() => {
// Consumer can anchor the popper to something that isn't
// a DOM node e.g. pointer position, so we override the
// `anchorRef` with their virtual ref in this case.
context.onAnchorChange(virtualRef?.current || ref.current);
});
return virtualRef ? null : <Primitive.div {...anchorProps} ref={composedRefs} />;
}
);

Is there a reason why useEffect here doesn't have a deps array (line 85)? When I add [context.onAnchorChange] to the effect dependencies, the error seems to go away.

@gabrieljim
Copy link

any solution for this? running into the same using popover

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

No branches or pull requests