React Native for 2022 (Notes and Snippets)

This article is ideal for Intermediate React Native Devs. P.S. consider this content with a grain of salt, share feedback too!

Introduction

React Native is an open-source JavaScript framework based on React to build Apps on multiple platforms (Android, iOS, and Web Apps) while utilizing the same code base! The motto of React Native is to "Learn Once, Write Anywhere". There have been tremendous advancements in this technology, some of which I would like to tap upon here.

Important terms: React Native, Hermes, JS Bundle, Native UI, Shadow Tree, JSI, Turbo Modules, Fabric Renderer.

React Native used to run on JavaScriptCore Engine, but a lot has changed in recent times. Now, the React Native team has developed their own JavaScript Engine in C++ called Hermes, which is a lightweight and optimized engine for React Native that results in improved start-up time and TTI (Time to Interactive), decreased memory usage, smaller app bundle, and faster execution in most cases.

React Native can be divided into three segments: JS Bundle (consists of all JavaScript Code), Native UI (Buttons, Scroll features, etc.), and Shadow. The JS Bundle cannot interact with the Native UI directly, the interaction was done via a Bridge, where everything is mandatory to be done asynchronously and data is serialized as JSON from JS Bundle to Bridge, and then deserialized from Bridge to Native UI. This mandatory JSON transformation resulted in bottlenecks and slow performance.

Then the introduction of JSI, i.e., JavaScript Interface, took place.

JSI (Javascript Interface)

The JSI is a unified, lightweight, general-purpose layer for almost any JavaScript engine. Written in C++, it eliminates the requirement of data to be serialized/deserialized into JSON for communication between JS code and UI, by holding references of native objects on the JS thread. This eliminates the chances of bottleneck by a huge margin since this stringification used to be a major factor of bottlenecking.

One thing we all know is that JavaScript might be fast, but C++ is faster. Earlier, there were many performance issues, e.g. many threads and jumps across them: JS, Shadow, Main, Native, etc., and the JS and Main threads did not directly communicate (slow UI rendering).

The JSI provided the following advantages:

  • Sync call from JS thread to Native and vice-versa
  • Fast rendering using a direct call to UI Main thread
  • Data sharing between threads

Earlier, all rendering and positioning were done using Shadow thread (also known as Shadow Tree) which calculated the layout of elements and was coupled with the bridge. Now, JSI is also used in the rendering of UI elements using the Fabric renderer as the UI manager. The Fabric renderer is interoperable with JSI and Turbo Modules (allows lazy initialization of packages, thus faster startup time of apps) and allows to render the UI without stringification at all, providing truly native-like performance.

"Decoupled" Snippets for React Native:

  • React Native uses React library, but not ReactDOM as the render, the package react-native itself is a renderer.

  • ReactJS has react-router for navigation, React Native has Stacks (with swiping animations), which has a navigation container where the first Stack component will get rendered first (unless coded explicitly), and each component can use the hook useNavigation for navigation to other containers and also transfer props between them.

  • There are various types of Screens that we can use for navigation based on our use case, such as push, pop, modal, lightbox, etc.

  • Flatlist is a great way to render a list of data as compared to the traditional map method since it provides lazy loading. However, there might be performance issues in Flatlist as well, as the data size increases. To optimize Flatlist performance, we can: use pure components or memo, use cached optimized images using libraries such as react-native-fast-image, provide height value for every item so that Flatlist doesn't need to calculate it, avoid any extra work in renderItem function, and also avoid inline functions otherwise they are recreated every time component renders.

  • Tailwind is not completely present in React Native, (e.g. for displaying shadows), so we can use styled-components and fuse it with others, e.g. style={ [tw("...") , styledcomponents]} where tw is tailwind-rn library.

  • React Native does not have inbuilt Grid functionality or @media queries, so it may get tricky for platforms. We might need to use JS to track screen dimensions and render accordingly.

  • Some important modules for Chat Screens: KeyboardAvoidingView, TouchableWithoutFeedback (Chat Flatlist where onPress will trigger keyboard.dismiss()).

Do share your feedback, any suggestions and critics are welcome :)