Skip to main content
React Native Architecture

Module Overview

Estimated Time: 2-3 hours | Difficulty: Beginner | Prerequisites: JavaScript, React basics
Before writing any code, it’s crucial to understand how React Native works under the hood. This knowledge will help you debug issues, optimize performance, and make better architectural decisions throughout your React Native journey. What You’ll Learn:
  • What React Native is and how it differs from other solutions
  • The JavaScript-to-Native bridge architecture
  • The new architecture (Fabric, TurboModules, JSI)
  • Hermes JavaScript engine
  • When to choose React Native for your project

What is React Native?

React Native is an open-source framework created by Meta (Facebook) in 2015 that allows developers to build truly native mobile applications using JavaScript and React. Unlike hybrid frameworks that use WebViews, React Native renders actual native UI components.

True Native

Renders to real native components (UIView, TextView), not web views

Cross-Platform

One codebase for iOS and Android with 90%+ code reuse

Hot Reloading

See changes instantly without rebuilding the entire app

JavaScript

Use the language and ecosystem you already know

Large Ecosystem

Access to npm packages and React libraries

Active Community

Backed by Meta with millions of developers worldwide

Who Uses React Native?

Meta

Facebook, Instagram, Messenger

Microsoft

Office, Outlook, Teams

Shopify

Shop app, Point of Sale

Discord

Mobile apps
Other notable companies: Coinbase, Pinterest, Bloomberg, Walmart, Tesla, and thousands more.

How React Native Works

The Rendering Pipeline

When you write React Native code, here’s what happens:
┌─────────────────────────────────────────────────────────────────────────────┐
│                    React Native Rendering Pipeline                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   1. Your React Code                                                         │
│      ┌──────────────────────────────────────────────────────────────────┐   │
│      │  const App = () => (                                              │   │
│      │    <View style={styles.container}>                                │   │
│      │      <Text>Hello, World!</Text>                                   │   │
│      │    </View>                                                        │   │
│      │  );                                                               │   │
│      └──────────────────────────────────────────────────────────────────┘   │
│                              │                                               │
│                              ▼                                               │
│   2. React Reconciliation                                                    │
│      ┌──────────────────────────────────────────────────────────────────┐   │
│      │  React creates a virtual DOM tree and calculates the minimal     │   │
│      │  set of changes needed (diffing algorithm)                       │   │
│      └──────────────────────────────────────────────────────────────────┘   │
│                              │                                               │
│                              ▼                                               │
│   3. Bridge / JSI Communication                                              │
│      ┌──────────────────────────────────────────────────────────────────┐   │
│      │  Changes are serialized and sent to the native side              │   │
│      │  (Legacy: JSON over bridge | New: Direct JSI calls)              │   │
│      └──────────────────────────────────────────────────────────────────┘   │
│                              │                                               │
│                              ▼                                               │
│   4. Native Rendering                                                        │
│      ┌──────────────────────────────────────────────────────────────────┐   │
│      │  iOS: UIView, UILabel, UIImageView                               │   │
│      │  Android: View, TextView, ImageView                              │   │
│      └──────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Component Mapping

React Native components map directly to native platform components:
React NativeiOS (UIKit)AndroidWeb Equivalent
<View>UIViewandroid.view.View<div>
<Text>UILabelTextView<p>, <span>
<Image>UIImageViewImageView<img>
<TextInput>UITextFieldEditText<input>
<ScrollView>UIScrollViewScrollView<div> with overflow
<FlatList>UITableViewRecyclerViewVirtual list

The Legacy Bridge Architecture

The original React Native architecture uses a “bridge” for communication between JavaScript and native code:
┌─────────────────────────────────────────────────────────────────────────────┐
│                      Legacy Bridge Architecture                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   JavaScript Thread                    Native Thread                         │
│   ─────────────────                    ─────────────                         │
│                                                                              │
│   ┌─────────────────┐                  ┌─────────────────┐                  │
│   │  Your React     │                  │  Native UI      │                  │
│   │  Components     │                  │  Components     │                  │
│   │                 │                  │                 │                  │
│   │  - App.tsx      │                  │  - UIView       │                  │
│   │  - Screens      │                  │  - TextView     │                  │
│   │  - Components   │                  │  - ImageView    │                  │
│   └────────┬────────┘                  └────────▲────────┘                  │
│            │                                    │                            │
│            │         ┌──────────────┐           │                            │
│            └────────►│    Bridge    │───────────┘                            │
│                      │              │                                        │
│                      │  - Async     │                                        │
│                      │  - JSON      │                                        │
│                      │  - Batched   │                                        │
│                      └──────────────┘                                        │
│                                                                              │
│   ┌─────────────────┐                  ┌─────────────────┐                  │
│   │  JS Engine      │                  │  Native Modules │                  │
│   │                 │                  │                 │                  │
│   │  - Hermes       │                  │  - Camera       │                  │
│   │  - JSC          │                  │  - GPS          │                  │
│   │                 │                  │  - Storage      │                  │
│   └─────────────────┘                  └─────────────────┘                  │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

How the Bridge Works

  1. JavaScript Thread: Your React code runs here, handling business logic, state management, and UI declarations
  2. Bridge: Serializes messages to JSON and passes them asynchronously between threads
  3. Native Thread: Receives commands and renders actual native UI components
  4. Shadow Thread: Calculates layout using Yoga (Flexbox engine)

Bridge Limitations

The legacy bridge has several limitations that can impact performance:
  • Asynchronous Only: All communication is async, causing delays for time-sensitive operations
  • Serialization Overhead: Data must be serialized to JSON, adding CPU overhead
  • Single Bottleneck: All communication goes through one bridge
  • No Direct Access: JavaScript can’t directly call native methods
// Example: Bridge latency issue with animations
// This animation might feel janky because each frame
// requires a round-trip through the bridge

const opacity = useRef(new Animated.Value(0)).current;

Animated.timing(opacity, {
  toValue: 1,
  duration: 300,
  useNativeDriver: true, // This helps! Runs animation on native thread
}).start();

The New Architecture

React Native’s new architecture (available since RN 0.68, default in 0.74+) addresses bridge limitations with three key components:
┌─────────────────────────────────────────────────────────────────────────────┐
│                         New Architecture Overview                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    JavaScript Interface (JSI)                        │   │
│   │   ─────────────────────────────────────────────────────────────────  │   │
│   │   • Direct C++ bindings between JS and Native                        │   │
│   │   • No serialization needed                                          │   │
│   │   • Synchronous calls possible                                       │   │
│   │   • Enables Fabric and TurboModules                                  │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│   ┌───────────────────────────┐    ┌───────────────────────────────────┐   │
│   │      Fabric Renderer      │    │         TurboModules              │   │
│   │   ─────────────────────   │    │         ────────────              │   │
│   │                           │    │                                   │   │
│   │   • New rendering system  │    │   • New native module system      │   │
│   │   • Synchronous layout    │    │   • Lazy loading                  │   │
│   │   • Concurrent features   │    │   • Type-safe (Codegen)           │   │
│   │   • Better performance    │    │   • Direct JS-Native calls        │   │
│   │                           │    │                                   │   │
│   └───────────────────────────┘    └───────────────────────────────────┘   │
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                          Codegen                                     │   │
│   │   ─────────────────────────────────────────────────────────────────  │   │
│   │   • Generates native code from TypeScript/Flow specs                 │   │
│   │   • Type-safe bridge between JS and Native                           │   │
│   │   • Compile-time validation                                          │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

JavaScript Interface (JSI)

JSI is the foundation of the new architecture—a lightweight C++ layer that allows JavaScript to hold references to native objects and call methods directly:
// Conceptual example of JSI benefits
// Old Bridge: Async, serialized
bridge.call('NativeModule', 'getData', { id: 123 })
  .then(data => console.log(data));

// New JSI: Direct, can be sync
const data = NativeModule.getData({ id: 123 }); // Direct call!
JSI Benefits:
  • No Serialization: Objects are passed by reference, not serialized to JSON
  • Synchronous Calls: When needed, JS can call native code synchronously
  • Lazy Loading: Native modules load only when first accessed
  • Multiple Engines: JSI abstracts the JS engine, enabling Hermes, JSC, or V8

Fabric Renderer

Fabric is the new rendering system that replaces the old UI Manager:
┌─────────────────────────────────────────────────────────────────────────────┐
│                    Fabric vs Legacy Rendering                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   Legacy Rendering:                                                          │
│   ─────────────────                                                          │
│   JS Thread ──► Bridge ──► Shadow Thread ──► Bridge ──► UI Thread           │
│   (Async)       (JSON)     (Layout)          (JSON)     (Render)            │
│                                                                              │
│   Fabric Rendering:                                                          │
│   ─────────────────                                                          │
│   JS Thread ──► JSI ──► C++ Shadow Tree ──► UI Thread                       │
│   (Can be sync)  (Direct)  (Shared)          (Render)                       │
│                                                                              │
│   Benefits:                                                                  │
│   • Synchronous layout measurements                                          │
│   • Concurrent React features (Suspense, Transitions)                        │
│   • Better priority handling                                                 │
│   • Improved memory management                                               │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

TurboModules

TurboModules replace the old Native Modules system:
// Old Native Module (loaded at startup)
import { NativeModules } from 'react-native';
const { MyModule } = NativeModules; // Loaded immediately

// TurboModule (lazy loaded)
import { TurboModuleRegistry } from 'react-native';
const MyModule = TurboModuleRegistry.get('MyModule'); // Loaded on first access
TurboModule Benefits:
  • Lazy Loading: Modules load only when needed, improving startup time
  • Type Safety: Codegen creates type-safe interfaces from specs
  • Direct Calls: Uses JSI for direct native method invocation
  • Better Performance: No JSON serialization overhead

Codegen

Codegen generates native code from TypeScript/Flow specifications:
// NativeMyModule.ts - TypeScript spec
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  multiply(a: number, b: number): number;
  getString(): string;
  getObject(): { name: string; value: number };
}

export default TurboModuleRegistry.getEnforcing<Spec>('MyModule');

// Codegen generates:
// - iOS: Objective-C++ interface
// - Android: Java/Kotlin interface
// - Type-safe bindings

Hermes JavaScript Engine

Hermes is a JavaScript engine optimized specifically for React Native:
┌─────────────────────────────────────────────────────────────────────────────┐
│                    Hermes vs JavaScriptCore                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   JavaScriptCore (JSC):                                                      │
│   ─────────────────────                                                      │
│   Source Code ──► Parse ──► Compile (JIT) ──► Execute                       │
│                   (Runtime)  (Runtime)         (Runtime)                     │
│                                                                              │
│   Hermes:                                                                    │
│   ───────                                                                    │
│   Source Code ──► Parse ──► Compile ──► Bytecode ──► Execute                │
│                   (Build)    (Build)     (Ship)       (Runtime)             │
│                                                                              │
│   Hermes compiles JavaScript to bytecode at BUILD time,                     │
│   not at runtime. This means:                                                │
│   • Faster app startup (no parsing/compiling at launch)                     │
│   • Lower memory usage                                                       │
│   • Smaller app size (bytecode is smaller than source)                      │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Hermes Performance Benefits

MetricJavaScriptCoreHermesImprovement
Time to Interactive4.3s2.0s53% faster
Memory Usage185 MB136 MB26% less
App Size41 MB22 MB46% smaller
Benchmarks from Meta’s testing on a mid-range Android device

Enabling Hermes

Hermes is enabled by default in new React Native projects (0.70+). To verify or enable:
// app.json (Expo)
{
  "expo": {
    "jsEngine": "hermes"
  }
}
# ios/Podfile (React Native CLI)
:hermes_enabled => true
// android/app/build.gradle (React Native CLI)
project.ext.react = [
    enableHermes: true
]

React Native vs Alternatives

Comparison Matrix

FeatureReact NativeNative (Swift/Kotlin)FlutterIonic/Cordova
LanguageJavaScript/TypeScriptSwift/KotlinDartHTML/CSS/JS
UI RenderingNative componentsNativeCustom (Skia)WebView
PerformanceNear-nativeBestNear-nativeSlower
Code Reuse90%+0%95%+95%+
Hot Reload✅ Yes❌ No✅ Yes✅ Yes
CommunityHugeLargestGrowing fastDeclining
Learning CurveEasy (if you know React)SteepMediumEasy
App SizeMedium (10-20MB)Small (5-10MB)Larger (15-25MB)Small
Native AccessVia bridge/JSIDirectVia channelsVia plugins
Web SupportReact Native WebN/AFlutter WebBuilt-in

When to Choose React Native

✅ Your team knows JavaScript/TypeScript and React✅ You need to ship iOS and Android apps quickly✅ You want near-native performance with code reuse✅ You need access to the npm ecosystem✅ You’re building a startup MVP or enterprise app✅ You want to share code with a React web app✅ You need over-the-air updates (CodePush/EAS Update)

Real-World Decision Framework

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Technology Decision Framework                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   Question 1: Does your team know React/JavaScript?                          │
│   ├── Yes ──► Strong candidate for React Native                             │
│   └── No ──► Consider Flutter or Native                                     │
│                                                                              │
│   Question 2: Do you need to share code with web?                           │
│   ├── Yes ──► React Native + React Native Web                               │
│   └── No ──► Any option works                                               │
│                                                                              │
│   Question 3: Is performance absolutely critical?                           │
│   ├── Yes (games, AR) ──► Native or Flutter                                 │
│   └── No (most apps) ──► React Native is fine                               │
│                                                                              │
│   Question 4: Do you need OTA updates?                                      │
│   ├── Yes ──► React Native (CodePush/EAS Update)                            │
│   └── No ──► Any option works                                               │
│                                                                              │
│   Question 5: Timeline and budget?                                          │
│   ├── Fast & Limited ──► React Native or Flutter                            │
│   └── Flexible ──► Any option works                                         │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

React Native Ecosystem

Core Tools

Expo

Managed workflow with pre-built native modules, OTA updates, and cloud builds

React Navigation

The standard navigation library for React Native apps

React Native CLI

Bare workflow with full native code access

Metro

JavaScript bundler optimized for React Native
CategoryLibraryPurpose
StateRedux Toolkit, Zustand, JotaiGlobal state management
Data FetchingTanStack Query, SWRServer state and caching
FormsReact Hook Form, FormikForm handling and validation
UIReact Native Paper, TamaguiComponent libraries
AnimationReanimated, MotiHigh-performance animations
StorageMMKV, AsyncStorageLocal data persistence
TestingJest, DetoxUnit and E2E testing

Understanding the Threads

React Native runs on multiple threads:
┌─────────────────────────────────────────────────────────────────────────────┐
│                         React Native Threads                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   1. JavaScript Thread                                                       │
│      ─────────────────                                                       │
│      • Runs your React code                                                  │
│      • Handles business logic                                                │
│      • Manages state and props                                               │
│      • Single-threaded (one JS thread)                                       │
│                                                                              │
│   2. Main/UI Thread                                                          │
│      ─────────────────                                                       │
│      • Renders native UI                                                     │
│      • Handles touch events                                                  │
│      • Must stay responsive (60 FPS = 16ms per frame)                       │
│      • Platform's main thread                                                │
│                                                                              │
│   3. Shadow Thread (Legacy) / C++ Thread (New Arch)                         │
│      ─────────────────────────────────────────────────                       │
│      • Calculates layout using Yoga                                          │
│      • Determines component positions and sizes                              │
│      • Runs Flexbox calculations                                             │
│                                                                              │
│   4. Native Modules Thread                                                   │
│      ─────────────────────                                                   │
│      • Runs native module code                                               │
│      • Handles async operations                                              │
│      • Camera, GPS, file system, etc.                                        │
│                                                                              │
│   Performance Tip:                                                           │
│   Keep the JS thread free for UI updates. Heavy computations                │
│   should be moved to native modules or web workers.                         │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Thread Communication Example

// This runs on JS thread
const handlePress = () => {
  // This computation blocks the JS thread
  const result = heavyComputation(); // ❌ Bad - blocks UI updates
  
  // Better: Use native module or InteractionManager
  InteractionManager.runAfterInteractions(() => {
    const result = heavyComputation(); // ✅ Runs after animations complete
  });
};

// Even better: Use useNativeDriver for animations
Animated.timing(opacity, {
  toValue: 1,
  duration: 300,
  useNativeDriver: true, // ✅ Animation runs on UI thread, not JS thread
}).start();

Key Takeaways

React Native Renders Native

Unlike hybrid apps, React Native renders actual native UI components

Bridge is Being Replaced

The new architecture (JSI, Fabric, TurboModules) eliminates bridge bottlenecks

Hermes Improves Performance

Hermes compiles JS to bytecode at build time for faster startup

Choose Based on Team

React Native is ideal if your team knows React/JavaScript

Practice Exercise

1

Research

Look up 3 apps you use daily and check if they’re built with React Native (hint: check their job postings or tech blogs)
2

Compare

Download the same app on iOS and Android. Notice any differences in UI or behavior? React Native apps should feel native on each platform.
3

Explore

Visit the React Native Directory and browse popular libraries. Note which categories have the most options.

Quiz

Answer: React Native renders to actual native UI components (UIView, TextView), while hybrid frameworks render to WebViews. This gives React Native near-native performance and platform-specific look and feel.
Answer:
  1. JSI (JavaScript Interface): Direct C++ bindings between JS and native
  2. Fabric: New rendering system with synchronous layout
  3. TurboModules: Lazy-loaded, type-safe native modules
Answer: Hermes compiles JavaScript to bytecode at build time (ahead-of-time compilation), while JSC compiles at runtime. This means Hermes apps start faster because they skip parsing and compilation at launch.
Answer: Avoid React Native for:
  • Performance-critical apps (games, AR/VR)
  • Apps requiring immediate access to cutting-edge platform features
  • When app size is critical (RN adds ~10MB)
  • When you have dedicated native teams

Next Steps

Module 2: Environment Setup

Set up your development environment for iOS and Android development