bp123
bp123

Reputation: 3415

Maximum call stack size exceeded from loop

I'm in the early stages of producing a rectangle SVG that uses the rectangle shape. I'm generating the colours of the pixels using a loop that gets all the RGB colours in increments of 8. The returned array has 32,768 <rect /> in it. The code produces the desired outcome however I get an error in:

Chrome

Maximum call stack size exceeded
getTypeSymbol (react_devtools_backend.js:4828)

Firefox

too much recursion

From what I can tell this isn't a recursion problem, the function doesn't appear to be reloading. I think it's related to the size of the array.

Any thoughts on what I should do here, I've never seen this problem before.

function PixelColour() {
  console.log("start");
  let counter = 0;
  let x = 0;
  let y = 0;

  const colours = [];

  for (let red = 0; red < 256; red += 8) {
    for (let green = 0; green < 256; green += 8) {
      for (let blue = 0; blue < 256; blue += 8) {
        counter++;

        if (x < 256) {
          x++;
        } else {
          x = 0;
        }

        if (x === 256) {
          y++;
        }

        colours.push(
          <rect
            key={counter}
            x={x}
            y={y}
            height="1"
            width="1"
            style={{ fill: `rgb(${red}, ${green}, ${blue})` }}
          />
        );
      }
    }
  }

  return <Fragment>{colours}</Fragment>;
}

class Colours extends React.Component {
  render() {
    return (
      <div>
        <svg width="256" height="128" style={{ border: "2px solid black" }}>
          <PixelColour />
        </svg>
      </div>
    );
  }
}

Upvotes: 1

Views: 1045

Answers (1)

lawrence-witt
lawrence-witt

Reputation: 9354

It's not your function reloading (or rerendering) which is the problem per se; you're running into recursion within React itself. Specifically with the way that React devtools tries to reconcile the DOM in order to build a component map.

This is actually not so easy to replicate on codesandbox, since it appears to be using an experimental version of devtools, and this error only crops up when hot-reloading. The stack trace there is scheduleFibersWithFamiliesRecursively but on my local machine with the standard devtools extension installed I get mountFiberRecursively when the component mounts.

I did some digging and came across this github issue, and a PR addressing it which appears to have been abandoned for the time being. Perhaps if you go and give them a nudge they might take another look:

Getting maximum call stack exceeded on backend.js when rendering many elements.

Refactored backend renderer to remove most of the recursion

All you can do in the meantime is disable the devtools extension. I would add that even with it disabled, this component takes several seconds to mount on my local machine. If you don't take the calculation out of the render cycle (function body) then it is going to be run on every render. You're trying to mount 10s of thousands of DOM nodes which is never going to run performantly - even the PR above only supposes a limit of 15000.

I think a better idea would be to 1) calculate this well in advance if you can, perferably as hard-coded data and nowhere near the UI thread, and 2) draw to a canvas rather than creating nodes in the DOM.

Upvotes: 2

Related Questions