Cross post from my own blog post

The rise of Flutter brought doubt to the decisions for a new mobile project. This doubt did not exist back in 2016/17 when someone needed a cross-platform mobile solution. Back in 2016/17, there were fewer options¹, it was obvious that if you wanted a cross-platform solution with JavaScript you would choose React Native since it outperformed its competition.

We are no longer questioning the viability of cross-platform, we are now deciding which solution is best. React Native and Flutter are great options to choose from despite other possible solutions e.g. Xamarin and others.

What should one know before deciding which is the best option for their project's requirement?

Architecture

The first thing one must know is the core differences between React Native and Flutter. React Native, for each platform, renders native widgets, its JSX Components translates to native counterparts. This differs from previous attempts of using JavaScript to write mobile apps because despite using JavaScript to declare UI elements, under the hood React Native is rendering Platform Native UI Widgets.

Flutter in the other hand does not render native widgets. It relies on a rendering engine to paint 2D UI elements. Flutter's engine, written primarily in C++, provides low-level rendering support using Google's Skia graphics library². This architecture decision provides Flutter with low-level control of rendering, enabling it thus for possible performance improvements.

Most UI elements will not display much difference when rendered by a rendering engine or the platform's widgets. The difference is often noticed on elements that interact with Users. The native UI elements usually have unique behaviors on each platform. For example, screen transitions, on iOS the screens slide in, while on Android the slide feels more like a fade-in. Also Text Inputs, these have accessibilities built-in by the platform. The rendering engine has to create all the basic functionalities of the Text Input, copy and paste, the positioning of the cursor, and even displaying the text.

The React Native core team has commented that it was a conscious decision to render native widgets instead of rendering UI elements themselves, according to them, it never seemed like the right approach for the following reasons; They didn't want to reimplement everything provided by the platform; The amount of work required to reimplement everything and keep up with platform updates, including support to multiple OS looks, both new and old³.

While Flutter, on the other hand, it attempts to provide identical UI look and feel on all platforms, Reflectly, an App which was originally written in React Native, was rewritten in Flutter with this in mind⁴. Flutter enabled Reflectly Development team to write an App on iOS and expect the exact same look and feel on Android.

It is unneglectable the effort of writing a cross-platform solution as Flutter requires more resources than React Native. Flutter is trying to match Native UI widget's behavior and although they have released a 1.0 version, this is an ongoing work⁵.

Developer Experience

When does Developer Experience decide the technology to use on a project? Hopefully, always. Good developer experience enables the Development team to write better Software. It keeps Developers happy. React Native made a big impact on mobile development by introducing hot reload and a declarative UI framework⁶. These two points increased developer productivity and overall happiness.

After developing Mobile Apps for almost 3 years using React Native, using Flutter for the first time left me a great impression. It has done an amazing job at creating a great onboarding experience by providing Flutter Docter, Hot reload, and well documented Docs. It is safe to say that anyone with Mobile development experience can be productive with Flutter exceedingly fast.

The React Native developer experience is an ongoing improvement process. Until last year, the attention given to the open-source community and consequently Developer Experience if compared to the efforts given today were smaller. Since the end of last year, React Native's core team has made perceptible efforts in improving how it interacts with the Open Source community. These efforts can be noted by the "What do you dislike about React Native?" versions 1 and 2. Dan Abramov is currently in charge of revamping the hot reload module⁷ which has been subject to some bugs.

Available UI elements

Both Flutter and React Native provide all the UI elements you need, nonetheless, each has taken a different approach at this. Flutter tries to deliver first-class support to all the UI elements you might need, it has a long list of widgets⁷, its goal is essentially for you to not need any third-party integration, it encourages you to write your own Widget.

React Native on the other hand, since it is an App rendering Native UI Widgets, it is striving towards a lean core⁹, where React Native will host the minimum set of modules you need, and leave any other dependencies to be managed by third-party open source. With React Native, there is no overhead on integrating native Views or Modules, just the cost of the communication through the bridge which is the reason for an architecture rewrite codenamed fabric¹⁰.

React Native Lean Core strategy to some sounded like a bad idea, removing some of the UI elements from the main repo meant others outside of Facebook would have to step up to contribute. The Lean Core ended up being a positive surprise, All extracted modules have received maintainers and have been updated more than ever.

It is important to note that if your App requires a native UI View integration, Flutter is responsible for all the rendering, therefore, when you need to render a Native UI View, either Android or iOS, it must embed the view in Flutter's hierarchy. For iOS the Documentation notes that this is an expensive operation¹¹ and I'll add that for Android it should not be super smooth since embedding views is not straight-forward.

Upgrading

Breaking changes are the main problem when updating. React Native's longer life has displayed multiple moments of frustration due to updates. This is not unique to React Native, it is rather a Software Development problem. Despite Flutter's shorter existence, it has already encountered moments where it needed to introduce a breaking change¹³. On a survey by Flutter's Core team, it questioned its users if breaking changes for a greater good was acceptable¹².

There is evidence that both communities are doing it's best to solve the updating issues by providing clear documentation and tools to help. Flutter has provided a Github Wiki¹³ for such occasion. While React Native's Core team and community have created a tool¹⁴ and documentation to deal with this.

Despite Core teams efforts, they are not exempt from the issues caused by targeted platform updates. AndroidX has been the reason for much efforts to correctly adapt to it¹⁵.

Community

For open-source projects, a healthy community can be a strong asset. Although Flutter is quite new, it has gotten a lot of traction and it is growing. Evidence of its growth can be noted in Insights from Flutter's first user survey of 2019¹². React Native's community is quite strong, driven by the whole JavaScript ecosystem. Both receive contributions from external development teams, most notably React Native has received many contributions from Companies like Microsoft, Callstack, and Expo¹⁹. Flutter has many external contributions as well, however, we are not able to clearly identify where they are coming from. In this category, Flutter and React Native have displayed confidence.

Performance

Hundreds of posts have been written about React Native versus Flutter, all of them affirm that Flutter is more performant than React Native, however, they all lack benchmarks. All these posts base themselves off the logic behind

Flutter's architecture. In theory, Flutter is faster. The Dart code (both the SDK’s and yours) are ahead-of-time (AOT) compiled into a native, ARM and x86 libraries20, thus, it is consumed faster by native code. React Native JavaScript thread must cross a bridge through batched async calls every 5 milliseconds. React Native, in theory, is also trying to solve the bridge issue with Fabric, which would enable JavaScript to communicate faster and synchronously through host records held in C++.

If we wrote two apps, one in React Native and another in Flutter with a couple of screens you will not really notice a difference. Only one post that contained benchmarks was found on the internet¹⁶. It was a timer app, by looking at the benchmarks you can see that it displayed a very small difference between a Native Android, Flutter, and React Native. However, this post has a flaw, it did not evaluate the key points where performance really matters, which are Animation and large lists.

Animation is a key point for performance. User will perceive the lag on a slow device. By default, React Native will loose in this test, it comes with an Animated API that is written and runs on the JavaScript thread. There are many posts about how the Animated API is slow¹⁷. To solve this issue you can use React Native Reanimated which solves this by running everything on the native thread¹⁸.

Even with the possible improvement to animations with React Native, you can't deny the fact that Flutter is using Skia as a rendering engine. This is a very performant framework and in Flutter's release, it displayed the capability of rendering 120 FPS on an Android device.

With lists, Flutter also does an amazing job by providing an out of the box API specifically for large lists. ListView.builder delivers virtualization out of the box with really high performance. On React Native, you can achieve acceptable performance with FlatList, however, it requires some tweaking as you can see on the Optimizing FlatList Configuration post.

React Native Time to interaction on Android Devices has also been subject of questioning. Nonetheless, in an effort to improve this, Facebook employed resources towards writing a JavaScript Engine to improve its performance on Android devices. Hermes is a JavaScript Engine optimized for React Native.

Conclusion

Some other points should also be taken into consideration, like the ecosystem. JavaScript is one of the most popular and used languages. On a recent project at G2i, the decision to go with React Native instead of Native development was mostly because we wanted to share all of the services and data logic already available in JavaScript.

Flutter and React Native are great tools for cross-platform development. Either one will deliver a high-quality Application.

About me

Hi! I'm a Software Developer focused on JavaScript. I love talking about Software Development, you can always reach out if you would like to chat.

Thank you for reading!

References

[1] Most only considered React Native or PhoneGap/Cordova, which were very different from each other, Flutter despite not being a JavaScript solution but with Dart, which is very similar to JavaScript in its C like syntax, was not stable to be considered.

[2] Wikipedia contributors. (2019, June 30). Flutter (software). In Wikipedia, The Free Encyclopedia. Retrieved 14:04, July 7, 2019, from https://en.wikipedia.org/w/index.php?title=Flutter_(software)&oldid=904189137

[3] Reactiflux QA React Core Team. (2019, January 24). In reactiflux.com transcript, retrieved from https://www.reactiflux.com/transcripts/react-native-team/#youitv-engine-one-currently-binds

[4] Reflectly App presentation. (2019, Mar 7). In Mobile World Congress 19, retrieved from https://youtu.be/hdOxvNQbies?t=746

[5] On July 7th, 2019, we can find the following issues in Flutter's repository related to UI elements behavior which would not exist if they were using Native UI Widgets: https://github.com/flutter/flutter/issues/35068, https://github.com/flutter/flutter/issues/35577, https://github.com/flutter/flutter/issues/35694. There are more this is just an example.

[6] We can see the evidence of this impact by the number of declarative mobile frameworks/toolkits which came after React Native. Flutter, SwiftUI, Jetpack Compose

[7] Widget index https://flutter.dev/docs/reference/widgets

[8] Ticket related to the broken hot reloading module https://github.com/facebook/react-native/issues/18899

[9] Ticket related to Lean Core https://github.com/facebook/react-native/issues/23313

[10] This is a good overview of the current bridge architecture, https://hackernoon.com/understanding-react-native-bridge-concept-e9526066ddb8. Issue corresponding the Fabric architecture https://github.com/react-native-community/discussions-and-proposals/issues/4.

[11] Embedding iOS views is an expensive operation and should be avoided when a Flutter equivalent is possible. https://api.flutter.dev/flutter/widgets/UiKitView-class.html

[12] Insights from Flutter's first user survey of 2019. (2019, April 11). In Medium post, retrieved from https://medium.com/flutter/insights-from-flutters-first-user-survey-of-2019-3659b02303a5

[13] Flutter's Handling breaking changes Wiki https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes

[14] React Native's Upgreade Helper https://github.com/react-native-community/upgrade-helper

[15] Flutter and React Native's evidence of AndroidX support efforts. https://flutter.dev/docs/development/packages-and-plugins/androidx-compatibility

https://github.com/react-native-community/discussions-and-proposals/issues/129

[16] Alex Sulivan - Examining performance differences between Native, Flutter, and React Native mobile development. Thoughtbot dev site: https://thoughtbot.com/blog/examining-performance-differences-between-native-flutter-and-react-native-mobile-development

[17] Various posts complaing of Animated performance: https://www.reddit.com/r/reactnative/comments/6ex9y1/brutally_slow_animations_on_android/, https://stackoverflow.com/questions/48928229/slow-animations-in-reactnatives-android-app

[18] react-native-reanimated https://github.com/kmagiera/react-native-reanimated

[19] React Native Repository Pull Requests from Amazon, Callstack, and Expo

[20] https://flutter.dev/docs/resources/faq#how-does-flutter-run-my-code-on-android