The New React Native Architecture Explained: Part Three
Part Three: Fabric and TurboModules
First announced in 2018, the React Native re-architecture is a massive effort Facebook undertook to address some long-standing issues of this cross-platform mobile solution.
In this series we will give an overview of the main elements that comprise React Native’s new structure. We will avoid showing code, to keep this explanation as accessible as possible, and will share our excitement regarding this new implementation.
In this post we’ll dive into the “meaty” part of the re-architecture, the one that every React Native developer has probably heard about: Fabric and TurboModules.
As we previously explored, the new React allows for the concept of queuing, and the JSI enables JavaScript code to be aware of the Native code “on the other side”.
For the sake of accessibility and easy comprehension, we’ll “oversimplify” what the bridge block of the old architecture is:
This group of elements is basically responsible for two different behaviours: defining how the UI should look and behave (via the Shadow Tree) and managing the native side (via Native Modules). As mentioned, these communications happen via asynchronous JSON messages that get batched and sent, back and forth, over one communication channel, which, as you may expect, can get congested and lead to suboptimal experiences.
The Facebook team decided to split this massive bridge into two separate actors: Fabric, which is the re-architecture of the UI manager, and the TurboModules, which is the “new gen” implementation of the interaction with native side.
Fabric aims to modernize the rendering layer of React Native. In the current implementation all the UI operations are handled by a series of cross-bridge “steps” (React -> Native -> Shadow Tree -> Native UI). The new implementation, however, allows for the UI manager to create the Shadow Tree directly in C++, which greatly increases the swiftness of the process by reducing the number of “jumps” across realms. Basically, this greatly improves the responsiveness of the User Interface.
Also, by using the JSI, Fabric exposes the UI operations to JavaScript as functions: the new Shadow Tree (which determines what to really show on screen) is shared between the two realms, allowing straight interaction from both ends.
And, if that wasn’t already a great improvement, this direct control from the JavaScript side allows to have the priority queues from the new React (mentioned in the first article) for the UI operations, in order to have opt-in synchronous executions where it benefits performance. This foundation will allow for improvements in common pitfalls like lists, navigation, and gesture handling.
In the current implementation, the Native Modules used by JavaScript code (e.g. Bluetooth) need to be initialized when the app is opened—even when they’re not used—because of the “unawareness” between the realms mentioned in the first article. The new TurboModules approach allows the JavaScript code to load each module only when it’s really needed, and to hold direct reference to it, meaning no more need to communicate using batched JSON messages on the old bridge. This will significantly improve startup time for applications with lots of Native Modules, along with the direct communication mentioned in the other articles.
All changes to the third block, as mentioned, rely on the JavaScript Interface explored in the previous article. If we want to sum up how the new Facebook team’s architecture looks like up to this step, it would look something like this:
This concludes the third part of our exploration of the re-architecture. Next week we’ll release the final post in this series. In the meantime, remember to share this article with your fellow developers or reach out for follow-up questions over on Twitter (DMs are open).
We hope we’ve sparked excitement on how these powerful changes will impact your codebases, without requiring any rewrites.
All aboard the hype train!
Other installments: