Slow rendering of large tables

We’re rendering everything with JavaScript rather than serving HTML directly (which would be done via Flask), so our upper bound for performance is React itself. In this case, React can load a datatable this big pretty quickly (here’s an example I made: https://codepen.io/chriddyp/pen/rNxYwNZ?editors=0110) so the bottleneck is still in our own code.

When we load a layout JSON, we crawl through the entire layout and perform some light checks on every single component before we render it. With debug=True, this includes performing verification that the properties supplied in each component (in this case, just children) are valid, which includes checking the names of the properties provided and their types. If the type is invalid (e.g. a dict was supplied to children instead of a string, component, or number) then we display an error message popup in the devtools panel. When debug mode is false, I believe if we’re still doing some checks like seeing if the component is in a loading state and needs the “is-loading” attribute. We also create a new data structure(s) that maps the IDs of the components to their location in the layout tree so that when we make a callback update, we can quickly address that component without needing to crawl the entire tree again on every callback (imagine if row 9421 and column 3 had a component with an ID that was updated via a callback. We don’t really know upfront where these components might be nested within the layout). Recursively crawling 40K items (A 10K table with 3 columns has 10K Tr elements, 30K Td elements) and performing these light checks & data structure initialization routines ends up taking a few seconds for large layouts. This used to take a lot longer but we optimized some of this code in 1.13.x by removing some of the checks. I’m a little hazy on the details here: I wrote the original version 3 years ago but it has since been reworked & improved by other engineers on the team.

As we’re crawling through the layout tree, we’re also generating the object for React to render: For each element, we call React.createElement recursively from the bottom of the layout tree up towards the root of the tree (40K function calls). It seems that constructing an object this way is slower than how React has been optimized to generate layouts with one big render, but we’d have to dig in here more to understand why. It might not be… it might be that the light checks that we perform during initialization is the main cause of slowness. The other engineers that did the latest performance improvements would know more here.

Then finally, we pass that object to React to turn that JavaScript object into actual HTML that you see on the page in the DOM. This itself is quite fast within the 10K-40K element range but will slow down above 50K-100K rows due to browser limitations with the DOM. Server-side frameworks (like pure flask) would have the same limitations here.