House
/
Blog
/
Flutter vs React Native: The Core Differences
React Native

Flutter vs React Native: The Core Differences

Learn the fundamental differences between Flutter and React Native, plus get a clear guide on which to pick based on your scenario.

Flutter vs React Native: The Core Differences

Flutter vs React Native Series

1. Flutter vs React Native: The Core Differences
2. Flutter vs React Native: Part Two
3. Flutter vs React Native: Part Three

By reading this series, you can expect to learn the fundamental differences between Flutter and React Native.

Cross-platform 

Understanding how cross-platform can be achieved will help you grasp how Flutter compares to React Native. 

How it has been historically achieved

Everything is rendered to a screen using a lower-level graphics language. 

To abstract away the lower level rendering of elements, original equipment manufacturers provide you with an SDK to build your user interface. 

Cross-platform normalizes the different ways to render a user interface by providing you with an API that abstracts away the details of rendering in different environments.

As an example, take the environment of an iOS app. You can choose to use their UI SDK UIKit, or you can use a lower-level rendering API called Metal. Android will use different rendering APIs and thus if you want a cross-platform interface your API will need to communicate with each platform's rendering mechanism.

The divergence in cross-platform solutions happens at two levels. The first level is the programming language, which one they choose to use. The second level is the rendering level, which layer they choose to access. 

Language-wise they can decide to use a lower-level language or not. Interpreted languages have a drawback related to its language engine needing to be included in the app's bundle. For example, JavaScript requires the inclusion of a JavaScript engine into the bundle. 

At the rendering layer, cross-platform frameworks can choose to use something lower level like graphics APIs (Metal, Skia, OpenGL) or use the provided UI SDK like UIKit on iOS and Android Jetpack on Android. 

Examples:

  • Xamarin does UI SDK binding and uses C# - a compiled language.
  • QT has its own rendering engine built with OpenGL and uses C++. 
  • Apache Cordova (PhoneGap) renders UI with the platform's provided WebView and uses JavaScript, an interpreted language (*Cordova is what powers Ionic).
  • Electron uses Chromium browser to render and interpret JavaScript. 
  • Tauri (New on the block) uses Webview, a tiny cross-platform webview implementation. It allows multiple languages to drive logic, as long as HTML & CSS are used for rendering.
  • Chromium renders to the page using its own rendering engine. 

Each decision on how you achieve cross-platform will yield a different drawback. In the end, there is no one solution to rule them all - they all just have different balances.

The core differences between Flutter & React Native

The core differences between Flutter and React Native lie in the languages of choice and rendering strategies.

At the language level, Flutter chooses to use Dart, which allows for runtime interpretation and ahead of time compilation. In contrast, React Native uses JavaScript - an interpreted language. 

At the rendering level, Flutter chooses to go lower level and implement their own rendering engine on top of Skia. React Native binds to the OEM's UI widgets by translating React Components into their native counterparts. 

These core differences pretty much dictate the main pros and cons of each solution. The pros and cons related to these two core differences won't be changed unless they revert the architectural decision, which they are likely to not change.

This is not to say that there are no other pros and cons. There are, specifically around tooling, SDK quality, and overall developer experience. The thing is, these other elements can be continuously changed or improved. As an example of such, when Flutter released its version 1 highlighting its "hot reload" feature, React Native already had this feature for years, but it degraded to a point of un-usability. But, months after Flutter's V1 release React Native fixed its "hot reload" feature. 

Upcoming articles to this series will cover the remaining pros and cons not related to the core differences.

Differences between the language of choice

Execution speed is likely to be the first highlight when it comes to comparing an interpreted language like JavaScript to an ahead of time compiled language like Dart. It is notorious that an interpreted language has slower execution since interpreting it during runtime has an overhead cost. 

The execution speed difference does decrease significantly with the support of Just-In-Time (JIT) compilation of JavaScript, which is supported by most JavaScript engines. 

Interpreted languages have the benefit of being more flexible, offering more features like dynamic typing and smaller program size

Due to the difference in execution speed, Facebook has specifically put effort into improving JavaScript Engines. As a result, they created their own. Hermes improves JavaScript's execution speed by precompiling it during build-time to efficient byte-code.

The creation of Hermes does not, however, entirely remove the overhead. The generated byte-code is not as efficient as it could be for the purpose, because it is hard to compile JavaScript, a dynamically typed interpreted language, into byte-code.

It is important to highlight that while compiled languages can be naturally faster, for a common user of your application this is not perceptible. You will see what I mean in the last portion of this post.

Other differences are more related to developer ergonomics and which language you prefer. JavaScript has more developers who feel comfortable with it, while Dart, a younger language, is steadily increasing in popularity. 

At the language level, they also differ when it comes to static types. Dart is statically typed and has recently introduced a sound null safe approach which increases its safeness by preventing null errors. Of course, you can always use TypeScript when it comes to JavaScript. 

There are differences, but they are not as relevant as it seems and your choice will likely be influenced by personal preferences instead of facts. Teams fluent in JavaScript will always be biased towards JavaScript and vice-versa. From my experience, I noticed developers with a background in compiled languages often feel more comfortable with Dart than JavaScript.  

Differences between the rendering of choice

The UI will be different and the runtime costs too. 

When you use a OEM provided UI element you inherit its default styles and behavior. When you don't use a OEM provided UI element, you define the default styles and behavior. There are pros and cons to both approaches. 

One of the benefits of using a provided OEM UI element is you have a lot of work done for you, especially around behavior. Whenever there is a version update, you benefit from the thousands of hours that platform puts into these UI elements, perfecting the behavior and look. 

Whenever someone says "have a native look and feel" they mean looking and behaving like the other native apps using the provided OEM UI. 

A drawback to using OEM UI is that each platform will look and behave differently. For cross-platform, this is an architectural decision you must make. Do you want your UI elements to be exactly alike independent of the platform? Or do you want the UI to look native, similar to the OEM UI? 

While it does seem rational to say we want the UI to look the same across any platform, design teams don't always agree. As a result, Flutter tries to mimic the targeted platforms native UI behavior and feel by offering themed UI kits. 

Having lower-level control of rendering allows for more possibilities. We need to understand that the provided OEM UI elements weren't ever intended to be used for intensive graphics activity. You shouldn't code a game using UIKit. Games or any other intensive graphics activity is done by using lower-level rendering APIs like OpenGL. 

I would argue that Flutter does lower-level rendering for three reasons: a) to have fine control over how things look across all platforms, b) be easily expandable into other platforms, and c) to guarantee higher frames per second.

Flutter's architectural decision to do lower-level rendering with Skia makes it easier for it to expand to new platforms. All they need to do is make sure the new target supports the Skia back-end - which they usually do since it leverages OpenGL.

The guarantee of higher frames per second can be overkill. The thing is, most apps operate at 60FPS without any optimizations. This is because they are not doing anything intensive. This becomes more of a concern when you are doing very intensive animations. 

I don't have a single app on my phone that has an intensive UI animation that would require lower-level rendering. And Flutter's first announcement around how it could achieve 120fps felt unnecessary for the common purpose of 2D UIs. 

Perceived Performance

When it comes to 2D UIs, the final outcomes will look great for either solution you use.

React Native
Flutter

As you can see, these two apps are performant and look great. While Flutter can achieve higher performance due to its fundamentals, this performance will only be relevant for very UI intensive operations that are rare for a 2D app.   

There's More

So far, I’ve covered that what differentiates Flutter from React Native will be the final UI look and feel. Plus, your preferences around the language used for development also come into play. 

To further explore the differences between not only the language but also the patterns and mental models to build UIs, we want to see samples of how code will look when we use each framework. Read Flutter vs React Native: Part Two and Part Three.

References

React

Looking for the best pre-vetted developers?

We have React, React Native, and Node.js developers available on a contract or full-time basis.

Group

Related Articles