As someone with a shallow grasp of rendering in general, it amazes me that we can achieve near 60fps for these insanely detailed games with tons of 3D objects, and yet we find it difficult to do the same with 2D UI rendering.
The bottleneck is typically CPU <-> GPU transfer. If your UI is processing data on the CPU, that information has to be shuttled over the GPU. On a platform like iOS (or MacOS) the core text rendering frameworks are built on the CPU. Text rendering, for instance, is complicated and despite a lot of experience with both native iOS development and recently with compute shader development, I couldn’t really throw out an estimate of how involved it would be to recreate something like CoreText fully on the GPU. And unless you give up CPUs, you’re still left with the problem of transferring data back and forth.
More and more gets ported to the GPU through parallelized algorithms, and smart GPU memory usage — but CPUs still offer a lot in their ability to do generalized computing.
This is why as I’ve gotten older I’ve come to really respect Computer Science fundamentals; the more you understand how to make the most of resource constraints — whether time, or memory, etc — the more magic you can make.
The overhead is much, much lower in native development. Having a JS bloatware adds a lot of slowdown, as does the additional nonsense layers of React Native itself. As you can see, RN developers are still boasting “60fps animations” in 2020.
Also I believe the traditional drawing algorithm (e.g. the painters algorithm) is not well suited for parallelization and how gpus do work. So the gpu is “fast” at slapping a circle texture on a couple of triangles, but rendering a circle from vector data not so much.
I think Apple has said that Core Animation (and maybe Core Graphics) now use Metal where possible, but vector to bitmap rendering is still done on the cpu.
Native framework (I'm familiar with Android) will just issue a translation coordinate change for the rendered view in this scroll. So there's no CPU <--> GPU transmission here because the view is already rendered in a texture and compositor will just move it a bit.
If web frameworks really reupload the whole view to GPU on each frame, it's no wonder all apps run like arse and burn battery.
They don‘t, but you also can‘t prepare (and download) a whole list of (tens of) thousands of items, which is why you only do the parts that are going to be scrolled in next. Both react native and standard native apps do this, but standard native apps are much better at it.
This seems to be one of those react native holy grails; I've been building an emoji picker similar to the one Slack uses but it's been a chore! I recently discovered Modalize, and it's working fairly well, but for a long SectionList performance was abysmal; there's so many levers to pull with any of those VirtualizedList components it's tough to tell if it was me or modalize.
It's around 8 emojis per row; FlatList can do multiple columns out of the box, but in order to allow scrolling through all categories I was forced to use SectionList to get the headings. Chunking the larger data array into groups of 8 and rendering them as single columns worked well enough, but the perf was abysmal, and it wasn't immediately clear why. I've found all of the VirtualizedList components are an absolute nightmare to perf tune, so I replaced the SectionList with a ScrollView and instead force users to tap on categories to switch.
There’s a small asterisk to this in that it says “No Native Dependencies”
.” This is true for Expo which comes with a couple of libraries for Reagt Native with native bindings to iOS and Android (and also for Web)
A lot of fluid animations and interactions in React Native are finally not that much of a hurdle anymore thanks to react-native-gesture-handler and reanimated, which are brilliant abstractions that fully offload work to the native thread and don’t interrupt interactions due to work on the main thread.
React Native’s own primitives, like Animated, can only go so far until they require intervention or activation from the main thread.
These libraries by Software Mansion have basically become a “must have” for creating compelling apps in React Native.
I just really recommend to use our library (https://github.com/openland/react-native-fast-animations) for non interactive animations like appearing and disappearing. Since iOS and Android could block UI thread during initial layouting if there are a lot of content and you will get dropped frames or just broken animation (if freeze will be ~200ms).
This is important since iOS actually rely that all animations are done via Core Animation that could not be blocked by main thread and therefore a lot of UI widgets are just slow on first view. Most iOS developers don't care if instantiating view will take 50ms since you have 300ms budget for all transition animations.
This library does same thing for Android by "hacking" native API the same way as official Google Apps do. This is a shame that google not opening this API.
No problem, you write this code once and reuse everywhere and you fixing bugs for all apps instead of hacking all by yourself for each platform. After coding for more than 10 years RN approach is so much better than native one.
I have built native interfaces that would interface C# code, that was slightly less pleasant as a developer experience while I would get a 100% native experience for the user and a better programming language in return.
So what you gain in getting a singular code base for at least your logic and data parts you lose because you're chasing bugs that would never happen if you would have used a better programming language.
The average native project I've seen had 5-15 dependencies. The average React Native project thousands and thousands of them.
Our app is much better written in RN than the one i built in native code. RN doesn't have native bugs - they are worked around unlike pure native development when you have to live with them. Have you tried to customize UINavigationController to run on every version of iOS? Almost all projects i have seen eventually replaced it altogether with a custom implementation.
Typescript IS better programming language and much more powerful than, say swift. I can't see whats so special about swift comparing to typescript. I was coding for 5 years on swift and know what it is. Tests are much easier, typesystem is much more powerful and flexible. Compilation times are instant comparing to native.
Please, don't rant on JS ecosystem and "dependencies". To build native app you download 30GB xcode, clang and god know how many different libraries and runtimes. JS just not install them globally and 90% of deps are for development only.
Our app have 700kb of compiled JS. I have NEVER ever able to fit my kotlin/swift app to 700kb of compiled binary (excluding libraries).
I stopped measuring sizes unfortunatelly, since nowadays you can cut heavy native part to pieces and deliver them separately and native part is out of my concern. We use webrtc anyway, so it won't be super light.
I could recommend RN if you can tolerate slightly lower performance (because of the stuff i mentioned earlier) and beware that infinite lists are absolute shitshow (we built our own). If you are native specialists you can write bindings by your own and replace only parts of the app with RN.
Assets are stored the same way as in native, not sure how you can do something with them.
Can’t remember the last time I had problems with UINavigationController besides the introduction of large titles but I can imagine you need to roll your own sometimes.
> Typescript IS better programming language and much more powerful than, say swift.
> Tests are much easier
Good because you’re going to need to write a shit ton just to verify everything that is verified for free by the compiler in Swift.
> typesystem is much more powerful
In what way?
> and flexible.
...because it’s not that strongly typed
> Compilation times are instant comparing to native.
Objective-C was much faster too, because it moved a whole class of bugs to runtime instead of compile time
> don't rant on JS ecosystem and "dependencies"
We could just as well shut down HN if you’re not even legally allowed to rant on the bat shit crazy JS dependency trees anymore.
> To build native app you download 30GB xcode, clang and god know how many different libraries and runtimes.
Actually it’s a relatively small application with a shit ton of simulators shipped with it. So apart from the dramatically inflated download size (like that was even needed given it’s real size) you probably already knew this yourself.
But nothing better than a whataboutism to cover up an inconvenient truth.
I actually got suckered into a point by point rebuttal where I already know where RN shines compared to native dev:
Reactive as it’s basic pattern and hot UI reloads.
This is so sad that i wasted time explaining something while you don't even know that typescript is statically typed language. That's the whole reasoning behind typescript.
It is more powerful because it flexible because it's typesystem is turing complete and you can describe literally anything in it. Everything is strongly typed. It is powerful because you can express anything unlike swift/java/kotlin where you are forced for some subset of what can do in typescript. For example, good luck enforcing string variable to specific values only. Good luck working with two classes that have same fields but don't have common interface with them. It is the fact - you can do much less in this languages than in TS.
Test also is the easiest thing to do in ts: i am coding for 20+ years and jest is simplest solution for tests ever. You just can't compare this to a shitshow of native testing (one is xcode because of xcode, another is android well because it is android).
I don't understand how python or erlang relate to discussion of ts on rn. You advising to write ios apps in erlang?
While you wasn't rational, i still tried to calculate how much i need to install to build anything with plain clang.
I got docker with ubuntu 20.20, base image is 78MB. Executed: 'run apt-get update && apt-get install -y clang python3' now image is 700MB. And i still don't have llvm, debuggers and anything i need.
The docker image of golang alpine is 350MB after downloading. Alpine itself is 5MB.
Typescript is a strongly typed language built on top of one that isn't, just like Objective-C gets all of the run-time problems that C has if you wanted them or not. There is no such thing as a free lunch.
Yes the very same way Swift exists because iOS devs are forced to use Objective-C (that have exact same flexibility of js) and Kotlin is simply because there are so many java projects and environments.
Swift has it's own run-time and used to ship it with every app built in it before the ABI was stabilized (and is still added for older versions of macOS and iOS if you target them). It still needs to interface libraries written in C and Objective-C and for that reason some parts of the language aren't as clean as I would like to see it, but otherwise UIKit and other libraries wouldn't have been compatible.
I ask because I'm looking to make a "native" app, and I'm debating between Swift and TypeScript + React Native. I haven't experienced many bugs from JS/TS, but that's because I try to avoid huge dependency graphs in my web apps. It would be concerning if React Native's dependencies were buggy enough to have to chase down multiple bugs per project.
This means there are many libraries just for date and calendar in JS that are really popular while everybody in Cocoa usually uses the ones already shipped with the OS because they work. This is why you see relatively few external dependencies on native apps.
Typescript fixes JS by adding types to the language but the runtime really doesn’t support them, so they’re kind of faked and built upon a leaky abstraction on top of JS.
This means there’s a larger possibility of runtime bugs where Swift and Kotlin offer a more secure type system, even compared to C++ and Java.
That makes sense. I'm usually secure with TypeScript because I try to use the strictest compiler settings, and try to use libraries with high coverage and/or written with TypeScript. Sounds like there are just too many libraries to audit for quality when using React Native.
Thanks for the information, I think I'll go with Swift.
have you actually looked at reanimated, which this uses, to see if that has the issue you describe? It sure doesn‘t block the JS thread, and I‘m pretty sure it doesn‘t block the "native" layout thread either? I‘m not 100% on that but I haven‘t seen it stutter, even on a bad android phone.
I am saying about blocking native main thread not js one for sure. 90% of the time people saying it is not shutter are 1) use very simple ui that does nothing or 2) it shutter they just have low bar for Android in general.
In my opinion bottom sheets are actually a far superior experience to the previous pattern of dialogs/modals or push screens:
- The user doesn't lose their navigation stack because they can tell the bottom sheet can be dismissed, they know where they "came from"
- The user keeps visual context on whatever triggered the bottom sheet, because they can still see what's behind it
- The user doesn't get forcibly navigated away from whatever they were browsing, they know that once whatever they're doing in the sheet is done, they can "go back".
My only complaint is that Apple added them to stock apps in iOS 12, so many iOS users got used to the pattern, but didn't provide an easy way to give the same experience for developers which creating a need for libraries like this.
I'm not defending dialogs or modals, but at least with those (on a larger screen) you have control over what hey cover.
I suspect most users wouldn't even know the bottom sheet is there nor how to bring it up nor how to dismiss it had they brought it up.
The visual context on whatever is underneath is lost once the sheet is brought up.
The user absolutely get forcibly navigated away; their context is shifted to the new layer which is slapped on top of the other layer. I can't count the number of times I either accidentally activated the bottom sheet or used it then got lost.
Bottom sheets are like hamburger menus; they are rugs that UX designers sweep all their baggage underneath.
It’s sorely needed at this point, it’s clearly a standard UI control now and countless developer hours have been wasted on it.
I’ve got several apps on my phone (maps, DoorDash, google maps, etc) all doing the same thing, but inconsistently and it’s infuriating. What makes iOS great (IMO) is consistency in UI patterns with things like navigation controllers, toolbars, etc. floating sheets are worthy of that treatment.
60fps and gesture handling is a breeze on iOS. There is nothing impressive about achieving this. We’ve had it for 13 years now on iPhones. We now have 120hz displays on iPads, and guess what, animations there are easy to achieve too, at 120fps.
Maybe you should let the amateur devs at Facebook and Pinterest know how easy it is? After all, they developed this entire framework in Objective-C to address UI performance, and – shocker here – they consider 60fps a selling point there, too.
Yes I’ve worked at FAANG companies, and yes it’s great Instagram used AsyncDisplayKit (which is archived by the way).
For most companies (maybe all), it’s not needed. Apple is doing a fantastic job abstracting views into SwiftUI and Android team is doing the same with Jetpack Compose.
Then what? More abstractions over abstractions to achieve 60 or 120 FPS through another framework?
And this is not related to the OP post, making these bottom sheets is a breeze. Literally:
1.) Custom ViewController with custom UIView as base view
2.) Add as child or present over root controller
3.) Translate and animate custom base view from bottom (top... left... whatever the hell you like)
It‘s about as easy to do what you describe in react native without performance issues, but like others have mentioned there is more to this pattern related to scrolling content, snap points, interaction with the content behind it...
I have the insight of 10 years of experience with developing complex iOS software. Facebook, like other big corporations, has a big tendency of over-complicating tasks. Case in point, React Native. The library you mentioned, AsyncDisplayKit, was an over-complication, which tended to create more performance issues than it solved.
The amount of useless negativity in this thread is really amazing. The repo has ~650 stars right now, so clearly developers are finding this work to be useful. Yet look at all the mindless poo slinging going on in this "community".
Do you use iOS? On Android I agree, but iOS seems to have adopted bottom sheets as a way to make up for it's lack of a back button, which means that you have to reach all the way to the top of the screen to dismiss a traditional modal, and it works pretty well.
Come September, when new iPhone comes with 90 or 120hz display comes out, web devs will be back to square one with these nonsense “60fps animations” “challenges”, which are the simplest thing to do in native development.
It seems to be more and more a niche tool. I don't think there's really anything better for situations where you have a small startup that needs an app, has JS experience, but can't justify a full-time mobile dev for each platform. This is the situation I'm in now, at least, and despite a few warts I couldn't imagine anything better for getting some fairly high quality apps out the door.
Not familiar with Ionic, honestly, and React Native has been around a few years and supported all the use-cases we'd want, and I've been doing React for a number of years, so a familiar environment was a huge win.
Energy consumption is definitely a concern, but our app isn't exactly something people are going to be on all the time...it's more of a "check it a few times a day and move on" sort of deal. It's a fairly complex app with quite a few screens and with daily usage I haven't noticed any hit on battery life.
A PWA could be a good fit, and while I think there's many cases where it makes a lot of sense, there's a handful of native features we wanted to utilize (most importantly, push notifications!) that aren't possible yet in the PWA world.
There's always tradeoffs with any of these abstractions and React Native fit the bill with what we were comfortable trading off. I'd love to see the whole thing get the full native experience on iOS and Android once we're profitable and can hire full-time devs on those projects, but we're not there yet and so far the decision to go with RN has paid huge dividends in terms of shipping this. You'd be hard-pressed to tell it wasn't a native app, seriously!
I haven't. Although I reckon there shouldn't be much difference performance wise, since all the heavy lifting is done on the native thread. Maybe it could potentially improve the mounting time, which is the only code JS has to run during the lifecycle of the component.