I’m building a frontend application using Purescript Concur React and I’ve run into a stack overflow, apparently somewhere deep in the guts of the Concur/React layers. The stack trace (below) from the browser is fairly opaque (to me). Are there tools or techniques people have used in the past to diagnose what is causing these issues?
To provide a bit more color, my code looks okay, but I am creating many nodes, some fairly deeply nested. In particular, I am rendering a widget for each item in a list, and this error only occurs when the list gets above a certain length.
Uncaught RangeError: Maximum call stack size exceeded
at Object.createElement (react.development.js:727)
at Object.createElementWithValidation [as createElement] (react.development.js:1792)
at foreign.js:140
at DOM.purs:21
at DOM.purs:21
at __do (Core.purs:47)
at foreign.js:12
at Left.value0 (foreign.js:12)
at __do (Types.purs:84)
at foreign.js:12
Playing with the x and y variables, I can pretty quickly figure out the limits on Chrome and Firefox (higher) and cause the stack overflow to occur. I tested it on TryPurescript as well to make sure it wasn’t something in my local versions/build – same result. To the extent it is relevant, I’m using a Linux build of Chrome, Version 84.0.4147.135 (Official Build) (64-bit)
Great reproducible example!
The magic number for me in TryPurescript with Firefox + Linux is 7130.
Unfortunately, I’m not enough of an expert in Concur nor React to identify what’s going wrong.
Unfortunately, the “solution” of mkLeafNode proposed in that example kind of eats the advantage of Concur. So I hope this isn’t some fundamental limitation.
Disclaimer: I am not familiar with Concur.
As far as I can tell A.range and Array’s map don’t have any stack-related issues like foldr. Their implementations use FFI to create one new Array with the changes in it.
Is there an issue with D.div'? I doubt D.text would be it.
If the implementation is using an argument spread for React children (fn.apply(...) in JS), then it’s probably too many arguments to fit on the stack. I had this problem recently at work.
That definitely seems to be the culprit, where @hdgarood found it in purescript-react.
This is getting a bit more afield, but can I ask how you replaced that call to apply?
I’m not a React expert, at all, and it looks like the alternative call to createElement directly would run into the same problem with the […children] parameter.
I’m not certain but I think React.createElement(class_, props, children) should have the same effect, although it might generate more warnings about elements not having keys.
In purescript-react, you would want to use the Dynamic DOM modules. These pass through children as a single array, but as @hdgarrood mentioned, you will get warnings from React if they are not keyed.