".map is not a function" error only on Android Pie? - reactjs

We are encountering a rather strange phenomena with .map in our React-Native (version 0.59.3) project: The APK runs well on various physical devices or emulators, but not on Android Version 9.0 where it crashes with
TypeError: o.map is not a function.
(In 'o.map(function(t,n){n.icon_color=A.white,
-1!==s.findIndex(function(n){return t.title==n.title})
&&(t.icon_color=A.red)})','o.map' is undefined)
This is how the error popup looks like:
We understand that this message appears if the variable on which we are applying .map is not an array, but we do indeed make sure that it is (and anyhow it works on various other versions and devices). What are we missing here?
Some background for the curious
We have two arrays, one is an array of data sets we obtain from an API response, and the other one is a list of bookmarked data sets from a local DB on the device. We apply the map functionality on the API response array and check if a certain item from the data set is present in the database of favorites. Based on this, we change the color of the icon. According to our tester, he did also have internet access, but we anyhow monitor #react-native-community/netinfo version 2.0.0.
Related questions
Error : .map() is not a function
React .map() is not a function error
https://www.freecodecamp.org/forum/t/map-is-suddenly-not-a-function/134196

This would only happen if o is not an Array.
You can check if o is an array using
Array.isArray(o);
More details about this here. It would be safe to rule out the possibility that it is a Android 9 specific issue. I have a Android 9 device and have tested map numerous times. If you are able to consistently reproduce only on Android 9, there is a chance there is something else into play when running on it. I'd suggest checking array existence using above^ method before you run a map on it.
Other options:
If you need to change the icon color of certain elements from your array, and just need those elements, you can use .find() if for single element and .filter() for multiple elements.
If you need the entire array as response, alternatives to .map() would be .forEach() and for of loops.
Happy to update the answer with more specific answers if you can update the question with your exact code (Even if it is not reproducible on desktop browsers)

As others have said, o is not an iterable object.
You need to check higher in the stack for the problem. If o is supposed to be an array returned by an API call then it is probable that the API call has failed, or the parsing of its response has failed.

Related

React error in render/flush: RangeError in flush RangeError: Maximum call stack size exceeded

I've been in the process of rewriting an old AngularJS app in React (actually it's using preact, chosen by the developer who started this project initially).
This app handles large deeply nested objects that get be displayed via Material UI accordions and tables. The data is more WIDE than deep, but at any rate, React has trouble rendering it all without this RangeError.
I've been dancing with this issue for a while now and have avoided it by strategically managing accordions and not rendering data for accordions that are not open.
I've commonly seen this reported as a recursion issue, and I've carefully reviewed the ode to confirm there is no recursion involved. Plenty of iteration, but no recursion.
Please note the stack trace, it's hitting this in the flush() function, which is not in our application code, but in the Chrome debugger VM. I've set breakpoints and it appears to be something related to DOM operations as the objects being flushed are React elements. Here's a code snippet from the point where this error is hit:
function flush(commit) {
const {
rootId,
unmountIds,
operations,
strings,
stats
} = commit;
if (unmountIds.length === 0 && operations.length === 0) return;
const msg = [rootId, ...flushTable(strings)];
if (unmountIds.length > 0) {
msg.push(MsgTypes.REMOVE_VNODE, unmountIds.length, ...unmountIds);
}
msg.push(...operations); <--- error occurs here when operations.length too long
And the stack trace logged when error occurs:
VM12639:1240 Uncaught (in promise) RangeError: Maximum call stack size exceeded
at flush (<anonymous>:1240:8)
at Object.onCommit (<anonymous>:3409:19)
at o._commit.o.__c (<anonymous>:3678:15)
at QRet.Y.options.__c (index.js:76:17)
at Y (index.js:265:23)
at component.js:141:3
at Array.some (<anonymous>)
at m (component.js:220:9)
The error is occurring if operations is too large. Normally it will be anywhere from a dozen or so in length up to maybe 3000, depending on what's going on, but when I try to load our page displaying the wide/deep nested object this number is more like 150000, which apparently is choking the spread operator.
My sense is that this type of app is a challenge for React. I cannot think of another example of a React app that displays data the way we do with this. If anyone here has experience with this sort of dataset and can offer suggestions as to how to make this work, please share.
My guess is I'm going to need to somehow break this object up into smaller chunks that represent smaller updates, but I'm posting here in case there's something I can learn.
It looks similar to this open issue on the React repo, only it happens in a different place (also in dev tools). Might be worth reporting your issue there too. So probably React is otherwise "fine" rendering this amount of elements, though you'll inevitably get slow performance.
Likely the app is just displaying too much data, or doing it inefficiently.
but when I try to load our page displaying the wide/deep nested object this number is more like 150000, ...
150000 DOM operations is a really high amount. Either your app really does display a whole lot of elements, or the old AngularJS app had too many wrapper elements and these were preserved. Since you mention it concerns data tables, it's probably the first reason. In any case complex applications always need some platform specific optimization.
If you can give an idea about the intended use case, or even better, share (parts of) the code, that would help others to give more targeted advice. Are the 150k operations close to what would happen in real world usage, or is it just a very inflated number for stress testing? Do you see any other performance regressions, compared to the Angular app, with very complex objects? How many tables are on the screen at a time?
A few hundreds of visible elements on the screen already gets quite cramped. So where would all these extra operations coming from? Either you're loading a super long page of which a user can only see a few percent at the same time, or the HTML structure is unnecessarily deeply nested.
Suggested performance improvements
I wouldn't say React isn't suitable for really large amounts of data, but you do need to watch out for some things yourself. React is only your vehicle to apply changes to the DOM. Putting a large amount of elements in the DOM is always going to lead to decreased performance, and is something you usually want to avoid.
In this case you could consider whether it's necessary to display all the table's data, which is probably the bulk of the operations. Using pagination would resolve the problem, and might even make it more user friendly.
If that's not an option, you maybe can use a library like react-lazyload to show/hide the items as they enter/exit the visible part of the table. To achieve this, use their unmountIfInvisible prop. You can then replace a complex data row with a single element that has the same height. The last is important to preserve the scroll height.
<LazyLoad
height={100}
offset={100}
unmountIfInvisible
placeholder={<tr height={100}/>}
>
<MyComplexDataRow />
</LazyLoad>
This way your data table never consists of much more complex elements than can be seen in the viewport. You probably need to tune the offset a bit so that it's always ready in time as it's benig scrolled.

Display/render Array contents organized with react or in a Web3UIkit component

I just recently started out with converting my web3 apps in NodeJS into web based apps using React and the Web3UIkit. But have a hard time getting into the flow of how React works and thinks with this states, rendering etc. I checked out the reactjs standard tutorials numerous times, and it all makes sense then, but in my particular use-case I cant seem to achieve what I want. Even not after trying numerous array examples from here.
The case:
I fetch all Ethereum mainnet transaction from block x until block y and filter/sort these into a Array. Then I count all transfer made on the same contract address to filter out hot/trending contracts only, and save the stats of it in a new Array with all the contractinfo like tokenname, counted transfers etc. Which all goes fine and I get the result I want whenever I console.log the array (see screen).
But now, I want to display the contents of this array organized and visually appealing trough React/Web3UIkit and let it update in realtime (or like each 5 seconds), but I cant seem to find a way in doing this properly. In fact, I cant even get any of the info from the array onto my screen.
I attached a screenshot to show what my console.log currently shows when I output, to give an idea how the information is stored and the array is structed. Anyone has any solutions which helps me to make sense of this? Hope so! Since I feel like I'm missing a piece in the puzzle, but cant find it.

using document.scrollTo a named element in next.js results in an document undefined error

I have an object that is used to to keep track of errors in a long form.
If you try to click on the submit button, and there is an error, I want to be able to scroll to that error by name.
I considered useRef, but each of these inputs are in a deep component structure, and it would need quite a lot of useRef's to be able to jump to them (and a significant rewrite of the inputs component library).
So, I figured I would just go with a simple pure javascript way:
function onClick(){
const errorInputName = Object.keys(errors)[0];
document
.getElementsByName(errorInputName)[0]
.scrollIntoView({ behavior: "smooth" });
}
The trouble is with Next.js document isn't always defined since it could run on the server side.
There seem to be plenty of ways to detect when document isn't available, but how can a force this one piece to run on the client side (even if a small delay is required).

Ext.create always returns Objects of the class "Ext.Class.newClass"

I'm trying to create Ext objects with "Ext.create" the Extjs version i'm using is 4.0.7 (updating would cause a lot of work i'm trying to avoid because the (css) skins for ie would need to be regenerated and tested).
Somehow everytime i try to create an Object of a specific type i.e. Ext.store.JsonStore with
Ext.create('Ext.data.JsonStore', {...config here...});
i get back an object of the type Ext.class.newClass without an error beeing thrown.
Does anyone know what can generally cause this problem? Or is this just the usual case and there will be no objects returned of the given type? I know that this is very little information but unfortuantelly even after a lot of research on the web and in the sourcode this is everything i have.

How can I take a programmatic screenshot of an Open GL ES 2.0 scene using GLKit (in iOS 6)?

I've found numerous posts regarding this, but I haven't been able to work out a solution, largely due to the fact that I don't have a very thorough understanding of OpenGL or GLKit.
I added the method described here to my project.
They specifically mention:
Important: You must call glReadPixels before calling
EAGLContext/-presentRenderbuffer: to get defined results unless you're
using a retained back buffer.
I tried unsuccessfully to set up a retained back buffer and given that doing so has 'adverse performance implications' I would rather avoid it.
The problem is, according to a comment in another post:
In GLKit, the GLKView will automatically present itself and discard unneeded renderbuffers at the end of each rendering cycle.
That being the case, how can I call the 'Snapshot' method at the appropriate time when using GLKit?
To date, in iOS 5 I get a weirdly yellow coloured version of the scene (as though there were no other colours) and in iOS 6 I get a pure white image (I imagine because I am using white as the clear colour).
Further, I have no idea what they (apple) are talking about in this comment:
// If your application only creates a single color renderbuffer which is already bound at this point,
// this call is redundant, but it is needed if you're dealing with multiple renderbuffers.
// Note, replace "_colorRenderbuffer" with the actual name of the renderbuffer object defined in your class.
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _colorRenderbuffer);
so I have commented out the call in my app. If it matters my objects are using VBOs with position, texture coords and colour.

Resources