Skip to content

Error: Maximum update depth exceeded #924

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

Open
2 tasks done
Atw-Lee opened this issue Feb 8, 2025 · 6 comments
Open
2 tasks done

Error: Maximum update depth exceeded #924

Atw-Lee opened this issue Feb 8, 2025 · 6 comments

Comments

@Atw-Lee
Copy link

Atw-Lee commented Feb 8, 2025

Describe the bug

I want to display the table in the dropdown。

I used the antd UI library

But they had a problem

Your minimal, reproducible example

https://codesandbox.io/p/devbox/infallible-smoke-8tc6d6?file=%2Fsrc%2Fmain.tsx%3A104%2C32

Steps to reproduce

click select

Don't use rowVirtualizer measureElement is normal

Expected behavior

Normal table rendering

How often does this bug happen?

None

Screenshots or Videos

No response

Platform

  • OS: [ macOS 14.6.1 ] - Browser: [Chrome 132.0.6834.160 ]

tanstack-virtual version

^3.12.1

TypeScript version

No response

Additional context

No response

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
@creage
Copy link

creage commented Mar 12, 2025

@piecyk This is very annoying bug. Help is much appreciated.

@dmezei
Copy link

dmezei commented Mar 19, 2025

In my case overriding the default measureElement function by specifying it in the options object made the issue go away. My overridden version simply returns the fixed height of the element (In my case it's a table with fixed height anyways).

measureElement: () => 40

My suspicion: the default version of this function in the lib uses element.getBoundingClientRect() to get the dimensions of the element. I think this can be pretty slow in certain circumstances.
https://github.com/TanStack/virtual/blob/main/packages/virtual-core/src/index.ts#L255

When items don't have the same dimensions:
I think, somehow IntersectionObserver (https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry/boundingClientRect) could be used to fix the performance problems causing this issue, however the solution would probably be a breaking change. measureElement expects us to return the measurement immediately. The solution with IntersectionObserver on the other hand would be asynchronous.

@piecyk
Copy link
Collaborator

piecyk commented Mar 20, 2025

@dmezei If the element has a fixed height, you don’t need to override measureElement. Instead, you can just avoid passing ref={virtualizer.measureElement}. However, if explicitly overriding it with a fixed height resolved the issue for you, that suggests there might be something else affecting measurement in your setup.

@piecyk
Copy link
Collaborator

piecyk commented Mar 20, 2025

@creage can you provide a small example to reproduce the bug on your end? That would help in diagnosing the issue more effectively.

@creage
Copy link

creage commented Mar 20, 2025

@piecyk The example in the description. Launch Chrome DevTools there, and click on the dropdown. It will crash with error:

Uncaught 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 checkForNestedUpdates (chunk-ZUX4WFZD.js?v=30649b61:19659:19)
    at scheduleUpdateOnFiber (chunk-ZUX4WFZD.js?v=30649b61:18533:11)
    at dispatchReducerAction (chunk-ZUX4WFZD.js?v=30649b61:12351:15)
    at Object.onChange (@tanstack_react-virtual.js?v=3998eb52:829:9)
    at Virtualizer.notify (@tanstack_react-virtual.js?v=3998eb52:319:65)
    at Virtualizer.resizeItem (@tanstack_react-virtual.js?v=3998eb52:594:14)
    at Virtualizer._measureElement (@tanstack_react-virtual.js?v=3998eb52:572:14)
    at Virtualizer.measureElement (@tanstack_react-virtual.js?v=3998eb52:607:12)
    at ref (main.tsx:311:37)
    at commitAttachRef (chunk-ZUX4WFZD.js?v=30649b61:17279:28)

The way we workaround it for now is by providing custom measureElement function, that will fallback to estimateSize when measuring of target item fails.

@piecyk
Copy link
Collaborator

piecyk commented Mar 20, 2025

The way we workaround it for now is by providing custom measureElement function, that will fallback to estimateSize when measuring of target item fails.

Yes, the issue here is that on the first render, the elements are positioned off-screen or hidden. Without a defined height, the virtualizer will continue rendering items in the list until they fit within the viewport.

One way to fix this is by checking if the element has a valid height and width. If it does, return the measured size; otherwise, fallback to the cached value:

measureElement: (element, _roEntry, instance) => {
  const cachedSize =
    instance.measurementsCache[instance.indexFromElement(element)].size;
  const rect = element.getBoundingClientRect();
  if (rect.height > 0 && rect.width > 0) {
    return Math.round(rect.height);
  }
  return cachedSize;
},

There were previous discussions about including this in the core, and overall, it should be configurable. For example, if an element in the list can be collapsed, we may want to explicitly set its size to 0.

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

4 participants