table: V 7.0.0 useExpanded hook: Error: Maximum update depth exceeded

Description: After updating react-table from 7.0.0-rc.16 to 7.0.0, I am getting an error when I try to expand a row Error: Maximum update depth exceeded.

Codesandbox example: https://codesandbox.io/s/lucid-bartik-u56pc

Steps to reproduce the behavior

  1. Go to the sandbox
  2. Click on šŸ‘ˆin the browser view
  3. See 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.

Expected behavior

  1. Go to the sandbox
  2. Change the version of react-table from the left-side panel to 7.0.0-rc.16
  3. Click on šŸ‘ˆin the browser view
  4. The sub-component (Expanded row) is rendered properly as expected

Screenshots image

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 8
  • Comments: 21 (3 by maintainers)

Commits related to this issue

Most upvoted comments

I had this issue, when I didn’t memoize both columns and data. Memoizing both fixed if for me.

Quick answer:

I can say with 100% certainty that if you are not memoizing your columns or data, you are not using React Table correctly. Everything in the docs and every example instructs you how to do this (as far as I’m aware). This is required so that React Table can knowingly optimize as much as computationally expensive work as possible for you while rendering the least amount possible.

Long answer:

I agree that a library should handle non-memoized values as best as possible, and React Table does that where possible. You’ll notice that for many values, you don’t have to memoize them even though the docs say too, and you’ll simply be opting out of a ton of performance optimizations. Your app may even run smoothly still in some cases. However, even in your own code, there are situations where you must memoize certain values or functions to avoid stack overflow. For example, it’s easy to see that if you don’t memoize incrementCount below, or set up some kind of condition to call it, you will stack overflow.

const [count, setCount] = React.useState(0)

const incrementCount = () => setCount(old => old + 1)

React.useEffect(() => {
  incrementCount()
}, [incrementCount])

This is in your own code, too, so even without React Table in the equation, you are still susceptible to this issue if you do not program for closures, rerenders, and memoization. When you develop a library like React Table that must be as performant as possible, you must rely on the built in performance mechanisms of the platform and their rules (React’s built-in useMemo and useCallback hooks in this case).

Unfortunately, there is no way to know for certain from within React Table if a value or callback is truly memoized (wow that would be great), and until that happens, it will be a possibility for people to not understand the documentation and/or API and not provide stable values/functions to React Table. At the end of the day, I can’t only do so much to ensure that users aren’t recreating values and functions on every render.

On the bright side, if you truly are sending in stable values to React Table and getting infinite rerenders or stack overflow, then you have absolutely found a bug and I will happily fix it! šŸ˜„

With that said, if you are sending in memoized values that you know are only changing when they should and still experiencing this bug, feel free to open a new issue with a codesandbox example demonstrating the issue.

there are many arguments that get passed into useTable that need to be memoized for everything to work properly or be performant.

I don’t know the underlying architecture of this library, but shouldn’t not memoizing something simply just result in worse performance, rather than a stack-overflow-type error. That’s what it seemed to do in 7.0.0.rc-16. I don’t know of any other library that requires memoization or else risk a crash.

Thank you everyone for the potential fix, but this still seems like a problem with the library. I don’t remember anywhere in the documentation that it says you must memoize columns. Even if it did, why should this be required. Personally I’m going to stay on 7.0.0-rc.16 until this is fixed properly.

It is actually in the documentation (https://github.com/tannerlinsley/react-table/blob/master/docs/api/useTable.md#table-options):

  • columns: Array<Column>
    • Required
    • Must be memoized

That being said, I agree that it is a usability issue but it is broader than just columns - there are many arguments that get passed into useTable that need to be memoized for everything to work properly or be performant. This is also an issue for many functional React components that use hooks; and as much as I like functional components and React hooks, it gets pretty annoying to have to wrap everything in useMemo or useCallback.

I agree that this is still a bug with react-table. šŸ‘ I mainly provided the memoization suggestion as a fix which acts as temporary workaround (although I think its a good practice in general).

I had the same error but was not using useExpanded. If I went back to 7.0.0-rc.16 it was fine, broken in 7.0.0. I then saw @timothymathison’s comment above, and saw that the columns weren’t memoized. This fixed it for me.

Same. Wasn’t using useExpanded but it’s still broke.

Thank you everyone for the potential fix, but this still seems like a problem with the library. I don’t remember anywhere in the documentation that it says you must memoize columns. Even if it did, why should this be required. Personally I’m going to stay on 7.0.0-rc.16 until this is fixed properly.

I had the same error but was not using useExpanded. If I went back to 7.0.0-rc.16 it was fine, broken in 7.0.0.

I then saw @timothymathison’s comment above, and saw that the columns weren’t memoized. This fixed it for me.

@Nizar-Rahme In your CodeSandbox example, you need to memoize expanderCol in Table.js. I did that and I don’t see the error any more: https://codesandbox.io/s/keen-sun-jgwrd.

This was happening to me as well during other state changes (misc react hook calls) …

Downgrading to 7.0.0-rc.16 resolved the issue for me

React documentation here clearly says:

You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to ā€œforgetā€ some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.

So I would consider this behaviour a bug in a library.

yeah, properly memoizing solved this for me too.

I had some… non obvious code that was breaking the memoization

const dependency = cleanArray(...)

const columns = React.useMemo(() => {}, [dependency])

where my cleanArray function was returning a new instance of the array every render.

Silly me šŸ¤¦ā€ā™‚ļø

Yes, for me use a useMemo on columns fix the problem !