React Native's re-architecture in 2020
How it will dramatically improve apps performance
React Native was first introduced in 2015 as a solution for developing cross-platform applications with native capabilities using the ReactJS framework. The original design of the platform did not come without its set of flaws and drawbacks, despite the solution gaining strong community support and seeing gradual increase in popularity due to the fame of its Web counterpart.
Originally announced in 2018, the React Native re-architecture is an undergoing effort by the Facebook team to make the platform more robust and address some of the most common issues brought by developers over the years. We'll take a look on how this re-architecture will affect and improve both app performance and development velocity.
The old architecture
- Displaying the UI correctly
- Accessing native capabilities
Typically, for the Android/iOS ecosystems, the mechanisms in place right now look a little bit like this:
There are 3 parallel threads running in every React Native app:
- The Native thread is responsible for handle the user interface. It communicates with the JS thread whenever there is a need to update the UI, or access native functions. It can be split into Native UI and Native Modules. Native Modules are all armed at startup, meaning that a Bluetooth module will always be bundled in case of use by React Native, even if it's not. It just wakes up when the app needs to use it.
- The Shadow thread is where the layout is calculated. It uses Facebook's own layout engine called Yoga to calculate flexbox layouts and send them back to the UI thread.
To communicate between the JS thread and the Native thread, we use the Bridge. Under the hood, this C++ module is mostly built around an asynchronous queue. Whenever it gets data from one of either side, it serializes the data as a string and pass it through the queue, and deserialize it on arrival.
What this means is that all threads rely on asynchronous JSON messages transmitted across the bridge, and these are sent to either side with the expectation (but not a guarantee) that they will elicit a response some time in the future. And there's also a risk of congestion.
Similarly, calculating a layout needs to go through many hoops before it can be displayed on the screen, as it needs to go all the way to the Yoga engine before it can be calculated by the native world. And this implies, of course, going through the bridge too.
The new architecture
In addition to improving considerably the communication between the different threads, this new architecture also allows for direct control over our native modules. Meaning that we can use native modules when we need them, as opposed to loading them all once at startup. This results in massive performance improvements of startup times.
This new mechanism could potentially also benefit many different use cases. As we have now the power of C++ in our hands, it's easy to see how React Native could be used to target a very large panels of systems.
And that's not all!
Over the years, React Native has accumulated a lot of parts that are now outdated, unused or otherwise legacy. With the main objective of cleaning the non-essential parts as well as improving maintenance, the React Native framework is seeing itself cleaned out of some its features. Meaning that core modules like Webview or AsyncStorage, are gradually being taken out of the React Native core to turn them into community managed repositories.
With a roadmap aiming at a complete re-structuration done in the next few years, I am excited to make my apps more performant and my developer experience much, much smoother!
A big thanks to Lorenzo S. for the help and overall knowledge on the topic.
If you'd like to go deeper, I highly recommend his talk on this subject from which the slides in this article are taken from: https://www.youtube.com/watch?v=7gm0owyO8HU