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.
Its the abstraction on abstraction culture which seems to be the norm these days, because, hey "ECMA script is portable and accessible"! So lets "browserify" all the things...
Just wait until your BBQ has its own browser - oh shit wait
> hey "ECMA script is portable and accessible"! So lets "browserify" all the things
It's not because JavaScript is portable or accessible (it's definitely not portable, and if you wanted accessibility you could do much better), it's simply because it's the most popular language.
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.
But apparently only in the bottom sheet. Scientist estimate, though, that humanity might be able to achieve 60fps scrolling in other app areas as soon as 2035, on a schedule right after cold fusion!
Try being less dismissive, you might be happier and make others happier while you are at it
Guaranteed good performance (the bit you picked up on) for a feature people want in an easy to use package sounds great. Well done the author and thanks for sharing your work.
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.
Are you building an emoji picker with each emoji per row, or multiple emojis per row? I'm wondering since there's virtualization libraries for lists, but not for grids.
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 tried to work with React Native and while there are many things that especially iOS development could learn from the developer experience apart from the fact that it's a platform-on-platform (with the associated problems the poster I initial replied to, I just can't get over the fact I'm working with Javascript and everything related to it.
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.
But most importantly this question - do you envision that building React Native apps requires one to write wrappers for native at some point ?
Or is it all abstracted away by now.
It depends, for us we write some wrappers in Kotlin and Swift, but this is irrelevant to team performance - this could take time, but 90% of the time work is done in typescript. You want to have some folks that can do hacking on native level.
We built our own since there are much better frameworks on native side - asyncdisplaykit on iOS and Litho on Android. This library claims 60fps without actually measuring it or using very simple layout. We are doing messenger and layouts are really heavy for rendering and rn have it’s limitations, more importantly we reuse lists between screens, we have our own micro react inside that renders mostly static content to json and send it to native side. This is overkill for some, but not for us. We would have done the same without RN anyway.
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.
Nobody would use Typescript if it wasn’t the least bad way to deal with Javascript.
> 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.
Nobody would use Typescript if it wasn’t for JS compatibility. Python and Erlang are similarly weak typed, easy to write tests for and way more mature than JavaScript based language will ever be.
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.
And if you didn't understand my argument about the fact that Typescript only exists and is used because people are forced to deploy to Javascript-only targets and are desperate to use something that is a bit more sane to work with I don't know what else to say. I've used Typescript, it has some great ideas I would love to see in Swift but at the end of the day the only thing it is is an extension of Javascript, which includes all of Javascript's failings.
If you like languages that have the properties of Javascript, there are better languages out there. Nobody would use Javascript if given an equal choice between all alternatives. Javascript is used because you have no other choice if you want to be compatible with browser-only targets.
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.
Typescript uses Javascript as it's runtime so inherits all of it's problems, Objective-C and C are 100% transparent to each other and for real masochists it's even possible to call Objective-C from C with an awful and clunky API. So you'll find most of C's problem in Objective-C while it's a much nicer to use language to express business logic and definitely much more compiler safe. Kotlin uses the same JVM as Java and inherits some of it's limitations (around generics for example).
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'm curious about the nature of your bugs. Are they the type of bugs that would be prevented by using TypeScript or knowing more about JavaScript, or were they bugs of your dependencies?
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.
JavaScript is very weakly typed. You can send an object to a function that expects an integer as an argument for example. Also there is no real standard library for a lot of things while Java, .net and Cocoa had them for decades.
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.
> 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.
I'm interested to read more about that, do you have an article or something?
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.
There's a difference between a dark pattern and a bad pattern. I don't think this is either, but it of itself is certainly not a dark pattern, one that's intentionally used to mislead.
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.
Expo comes with pre-installed native bindings. If you want to add native bindings to your expo app you need to eject. This means it does not use any native bindings not included in the Expo SDK.
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...
It's a bit more difficult to make it natively than what you've described if you want to track the users gesture and deal with content that also scrolls.
Not more than a few days of work to get right at max but still a bit more.
> they developed this entire framework ... to address UI performance
They developed it to address developer performance and ensure consistency.
Apple's layout APIs certainly could be a lot better but this framework only seems necessary if you want to avoid having the same teachable moments over and over for thousands of junior engineers.
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.
Pretty much this there are 400 active current issues in Texture, same issues when I worked at smaller companies who wanted to do the “cool” thing and follow FB.
meanwhile, I've made a small app with Flutter and loved it. Everything just works. Install it in 10 minutes and you're good to go. In flutter everything is a widget and creating your own widgets by composing other widgets makes so much sense. Seriously, you have to try it to appreciate it. Dart is also nice and easy for those familiar with Java and JavaScript.
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.
Apple Maps has vertical and horizontal(carousel) scrolling inside the bottom sheet. Apple is often regarded as the industry leader in mobile interaction design.
Why would you make a remark like this without any explanation or supporting argument? Please don't.
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.
Is RN still used widely? Most people/companies I know have ditched it. It's never a time saver and usually just a pain once you wanna do something complicated.
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.
Why don't you use ionic or a pwa? It is known that RN has an extreme impact on battery consumption, the web browser is much more efficient in terms of energy use...
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.
RIP native development, long live non-native native development?