React Native

Trainer

Marcin Kieruzel

I'm a Software Engineer.

I run a small software house in Warsaw Poland.

 

We do front-end and back-end development and graphic design. We specialize in React, React Native, Node.js, PHP and Python.

Beside programming we're training people in AI and JavaScript technologies.

Course outline

The course takes 5 days (4 hours per day)

During the course we'll have two small 5-10 min breaks

Day 1

● What is React Native?

  •  RN vs. native apps vs. hybrid apps vs. web apps
  • React Native architecture
  • Comparison of so called “old” and “new architecture”                            

● Environment Setup

  • Node, npm/yarn                                                                                            
  • Installing React Native CLI / Expo CLI
  • How to set up Android Studio/Xcode Simulators
  • Hermes – js engine for RN

 

 

● First App: Hello World

  • Project creation                                  
  • Folder structure walkthrough                                        

● Core React Concepts (Recap)

  • JSX                                                                      
  • Components
  • Props and State                                                                  
  • Hooks (intro)

● Hands-On

  • Building simple app                                                            
  • Hot reloading, debugging basics

My journey with React Native has started in 2019. At that time my company was working for National Polish Radio where we decided to move all their mobile apps to React Native.

This decision was at that time mostly founded on the fact that majority of the team had experience in React and frontend in general.

For nearly 5 years I was the head of a React Native team. We successfully shipped 7 mobile apps on both Google Play and App Store.

With lots of ups and downs of course :)

What is React Native?

Framework Overview

React Native is an open-source framework for building mobile applications.

Who uses React Native

Introduction to React Native

Building mobile apps using JavaScript

Comparison

Native apps – build with Java, Kotlin, Swift

Web based mobile apps (Hybrid apps) – basically are websites inside mobile app (Capacitor, Ionic, Phone Gap, Apache Cordova)

Cross-platform native apps – React Native, Flutter

 

 

React Native

  • Language: JavaScript / TypeScript

  • Rendering: Uses the native platform’s UI components via a bridge.

  • Architecture:

    • JavaScript runs in a separate thread.

    • Communicates with native modules through a JS Bridge (prior to so called new architecture)

    • JSI – synchronus C++ bindings

  • Performance: Good, but can suffer with complex UI or animations due to bridge overhead.

  • Examples: Facebook, Instagram, Discord (parts), Shopify

 

 

Flutter

  • Language: Dart

  • Rendering: Uses a custom rendering engine (Skia) to draw every pixel, including buttons, animations, etc.

  • Architecture:

    • No need for a bridge.

    • Compiles to native ARM code.

  • Performance: Excellent, often better than React Native for graphics-heavy or high-FPS UIs.

  • Examples: Google Ads, BMW, eBay Motors, Alibaba

 

 

RN vs. Native Apps

  • React Native: Cross-platform
  • Native Apps: Platform-specific

RN vs. Hybrid Apps

Hybrid apps combine web technologies with native features, while RN uses native components.

Performance Comparison

React Native offers near-native performance compared to hybrid and web apps.

RN vs. Web Apps

  • Web apps run in browsers.
  • React Native targets mobile devices.

Development Experience

  • Hot reloading for faster development.
  • Single codebase for multiple platforms.

Community and Support

Strong community support with numerous libraries and resources available.

Future of React Native

Continued growth and improvements expected in 2025 and beyond.

React Native Architecture

The first observation!?!

This is complicated!!!

We have native modules and code on Android and Ios, Java, Kotlin, Swift, Node.JS, C++, CSS, React. In short terms lots of technologies, platforms, tools and concepts. 

Fortunately you don't have to fully understand  the architecture to build RN Apps. But of course it's worth to have a glimpse. 

Most of the time good React knowledge and usage of Expo framework suffice for successful development. 

Let's start with quick overview. What is not first?

React Native is not a web based technology. It uses JavaScript/Node.js under the hood and even CSS but it doesn't  render html or webviews. 

Let's start with quick overview. What is not first?

React Native is not any kind of code/app generator. By that we mean that there is a javascript runtime in production app.

Actually RN uses many threads in an app.

  1. JavaScript Thread
  2. Shadow Thread (for Yoga engine)
  3. C++ Thread (for JSI)

Xamarin in other hand is mostly code generator (especially on IOS)

Comunication with Native (Turbo) Modules and UI Components

 

React Native uses those two terms (Native modules and UI Components) to describe the communication with platform specific functionalities of Android or IOS (Which are classes, functions, XML).

Native (Turbo) Modules – like Camera, GPS, Contacts
UI Components – View, ScrollView, Text

Comunication with Native (Turbo) Modules and UI Components

 

So from the perspective of RN the main goal is to communicate and manipulate bot UI Components and Native (Turbo) Modules. 

Old architecture

In this model, communication between JavaScript and native code (Android/iOS) happens through a Bridge.

 

1. JavaScript calls a native function

You call a method from JS, like:

NativeModules.ToastModule.show("Hello", ToastModule.SHORT);

Old architecture

2. Data is serialized into JSON

The function call, module name, method name, and arguments are packaged into a JSON message.

Old architecture

3. Sent across the Bridge (Asynchronously)

  • This message is passed to the native layer using the Bridge.

  • The Bridge is asynchronous and batched, meaning:

    • Calls don’t return immediately.

    • Multiple calls can be grouped to reduce overhead.

Old architecture

4. Native side deserializes and executes

  • Native code (Java/Swift/etc.) receives the message.

  • It maps it to a native method and executes the corresponding function.

Old architecture

5. Results returned (optional)

  • If the native function returns a value (e.g., via a Promise or callback), the result is sent back across the Bridge to the JS thread asynchronously.

[ JavaScript Thread ]
       ↓ (JSON message)
       BRIDGE (Async)
       ↓
[ Native Modules Thread ]
       ↓
[ UI/Main Thread (if needed) ]

Old architecture

Limitations of Old Bridge

Limitation ​Why It Matters
Asynchronous only Can't perform sync calls (like reading instant values)
Serialization overhead Converting to/from JSON slows things down
No shared memory Data must be copied, not referenced
Performance issues Frequent calls (e.g., animations) can lag

Understanding React Native’s New Architecture (2025)

  • Old bridge was asynchronous, JSON-based, and performance-limited

  • No shared memory or sync calls

  • UI and native modules could lag under heavy load

  • Needed for concurrent rendering, advanced animations, and better native integration

Key Concepts

ComponentRole in the Architecture

JSI JavaScript Interface for fast, sync access to native
Fabric New rendering engine for UI (replaces old UI Manager)
TurboModules Modern native module system with lazy loading
Codegen Auto-generates type-safe bindings for native modules

                                      Old Architecture               New Architecture

Communication JSON Bridge (async) JSI (sync + async)
UI System UIManager (batched) Fabric (concurrent)
Native Modules NativeModules (static) TurboModules (lazy, fast)
Data Format JSON serialization Shared memory (C++)
Tooling Manual bindings Codegen automation

JSI (JavaScript Interface)

  • C++ layer that connects JS runtime (Hermes/JSC) to native code

  • Enables synchronous function calls between JS ↔ native

  • Removes JSON serialization, making calls faster and more efficient

Fabric Renderer

  • New UI rendering system for React Native

  • Built for concurrent rendering (React 18)

  • Renders views directly with less overhead

  • Improves:

    • Performance

    • Layout consistency

    • Animation fluidity

https://reactnative.dev/architecture/fabric-renderer

Render, Commit, and Mount

The process of so called rendering is pretty complicated. If you'd like to dig deeper have a look at the link below.

https://reactnative.dev/architecture/render-pipeline

Cross Platform Implementation (Render pipeline)

React Shadow Tree (and React Shadow Node)

A React Shadow Tree is created by the Fabric Renderer and consists of React Shadow Nodes. A React Shadow Node is an object that represents a React Host Component to be mounted, and contains props that originate from JavaScript. They also contain layout information (x, y, width, height). In Fabric, React Shadow Node objects exist in C++. Before Fabric, these existed in the mobile runtime heap (e.g. Android JVM).

Yoga Tree (and Yoga Node)

The Yoga Tree is used by Yoga to calculate layout information for a React Shadow Tree. Each React Shadow Node typically creates a Yoga Node because React Native employs Yoga to calculate layout. However, this is not a hard requirement. Fabric can also create React Shadow Nodes that do not use Yoga; the implementation of each React Shadow Node determines how to calculate layout.

TurboModules

  • Replaces NativeModules

  • Native modules are now:

    • Lazy-loaded

    • Accessed via JSI

    • More efficient & modular

  • Enables fast access to device features (camera, sensors, storage)

Codegen

  • Developers define native module interfaces in TypeScript or Flow

  • Codegen:

    • Generates native bindings automatically (iOS & Android)

    • Enforces type safety

    • Reduces manual boilerplate

Thread Model

The React Native renderer distributes the work of the render pipeline across multiple threads.

Here we define the threading model and provide some examples to illustrate thread usage of the render pipeline.

 

The renderer uses two different threads:

  • UI thread (often called main): The only thread that can manipulate host views.
  • JavaScript thread: This is where React’s render phase, as well as layout, are executed.

https://reactnative.dev/architecture/threading-model

Getting started

ToolPurpose

Node.js + npm/yarn JS runtime + package manager
Metro JS bundler for RN apps
Xcode iOS development and simulator
Android Studio Android development and emulator
VS Code Code editor
Flipper Debugging (now supports Fabric)
Codegen Auto-generates native interface bindings

What is Expo?

Expo is an open-source framework and toolkit built on top of React Native. It simplifies mobile app development by managing native code, bundling, and deployment for you.

Key Features:

  • Built-in SDK for camera, notifications, sensors, and more

  • No need to configure Xcode or Android Studio to get started

  • Works across iOS and Android with one codebase

  • Includes Expo CLI and Expo Go for fast development and testing

Two Workflows:

  1. Managed Workflow

    • No native code

    • Use only supported Expo SDK features

    • Easiest to maintain

  2. Bare Workflow

    • Full access to native code (like traditional React Native)

    • Needed when adding custom native modules

    • Requires Xcode/Android Studio

 

Two Workflows:

Core Tools:

  • Expo CLI: Scaffold and manage your project

  • Expo Go App: Instantly preview apps on real devices

  • EAS (Expo Application Services):

    • Build production apps in the cloud

    • Publish OTA updates without app store review

 

Advantages and Limitations

Advantages:

  • Fast setup and development

  • Cross-platform with shared code

  • Large set of prebuilt APIs

  • Cloud builds and over-the-air updates with EAS

Limitations:

  • Can’t use all native modules in Managed Workflow

  • Must eject to access custom native code

  • Slightly larger app bundle sizes

 

 

Advantages and Limitations

When to Use Expo:

  • When you need to build quickly

  • When native customization is not required

  • When working with small teams or solo

 

 

Get started

npm install -g expo-cli        # Optional: Global install
npx create-expo-app MyApp --template
cd MyApp
npx expo start

JavaScript Engine

A JavaScript engine is the runtime that executes your JavaScript code inside a React Native app.

In web browsers, that's usually V8 (Chrome) or JavaScriptCore (Safari). In React Native, you choose the engine that runs outside the browser, directly on iOS/Android.

Key notes

React Native – cross platform framework for building native mobile apps in JavaScript environment. It's closes competitor is Flutter.

React Native – executes JavaScript code in the apps runtime communicating with Android and IOS platforms and external devices on a cell phone.

 

Two architectures

Old architecture – JS layer asynchronously communicates with Android/IOS platforms (with serialized JSON objects)

New Architecture – uses JSI (JavaScript Interface) for synchronus communication with Host Platforms.  Shares memory via C++ layer

 

Two styles of develepment

With Framework (managed workflow) – uses Expo as a framework


npx expo init MyFirstApp

Without Framework (bare workflow) – uses React Native directly, allows to access both IOS and Android code

npx react-native init MyNativeApp

Development devices

Web emulator – emulates mobile app in the browser
Expo Go – allows to see the app on real device (qr code for connecting)

Android Studio/XCode emulator – emulating device on a computer, close to reality but decreases computer resources
Connecting real device via USB or WiFi –  requires turning phone into dev mode and configure connection
 

Main React Concepts

JSX

One Way Data Binding
Shadow Tree (virtual dom)

 

 

Main React Concepts

Components – Think of components as reusable building blocks for your app’s UI.

State is like a component’s personal memory — data that changes over time and causes re-render when updated.

Props are inputs to a component — like function parameters, but for UI.

Hooks are special functions that let functional components use state, lifecycle, and other React features without classes.

 

 

Host Components

 

View Container for layout, like <div> in web
Text Displays text
Image Displays images
ScrollView Scrollable container
TextInput Input field for text
TouchableOpacity Pressable wrapper with fade effect
TouchableHighlight Pressable wrapper with highlight effect
   

 

 

Pressable Modern pressable wrapper with more events
FlatList Optimized list for large data sets
SectionList Grouped list view
Modal Displays content above other views
ActivityIndicator Loading spinner
Switch On/off toggle
StatusBar Controls status bar appearance
RefreshControl Pull-to-refresh for scrollable views
SafeAreaView Renders content within safe screen bounds
KeyboardAvoidingView Adjusts layout when keyboard is visible

Navigation

  • Stack

  • Drawer
  • Tab

 

React

What is React? 

➡️ React is a JavaScript library for building interactive user interfaces.

➡️ It is a free and open - source front - end Javascript library for building user interfaces based on UI components.

 

*By user interfaces, we mean the elements that users see and interact with on-screen.

*By library, we mean React provides helpful functions to build UI, but leaves it up to the developer where to use those functions in their application.

sources: Next.js.org & Wikipedia

What is React? 

You my think of React as a templating language, similar to Jinja, Blade, Twig or Blazor.

React originally work on a browser but modern React can be executed on the server and mobile environment as well.

sources: Next.js.org & Wikipedia

It also means, however, that building a complete React application from the ground up requires some effort. Developers need to spend time configuring tools and reinventing solutions for common application requirements.

source: Next.js.org

sources: Next.js.org & Wikipedia

Who created React and Why?

Original Author:  Jordan Walke 

Initial Release: May 29, 2013 | 12 years ago

 

Story: In 2011, as Facebook’s Ad app began to pick up major momentum, their code began seeing a myriad of new updates and team members which became overwhelming and hard to manage after a while. In an attempt to help remedy this problem, Jordan Walke created FaxJS, a prototype which made this process more efficient. This was the birth of what would later evolve into the version of React that we all currently know and love today.

 

Who created React and Why?

How to start?

Let's start with Hello World

import React from "react";
import { Text, View } from "react-native";

export default function App() {
  return (
    <View>
      <Text>Hello, world!</Text>
    </View>
  );
}

Main React Concepts

➡️ Virtual DOM 

➡️ JSX

➡️ One - Way Data Binding 

Virtual DOM (Shadow Tree)

What is DOM?

 

DOM - stands for Document Object Model

The DOM is an object representation of the HTML elements. It acts as a bridge between your code and the user interface, and has a tree-like structure with parent and child relationships.

This concept is used in React Native as well but in different environment. It's called Shadow Tree.

source: Nexj.js.org

source: Next.js.org

What is Virtual DOM or VDOM?

 

A virtual DOM object is a representation of a DOM object, like a lightweight copy.

It has the same properties as a real DOM object, but it lacks the real thing’s power to directly change what’s on the screen.

In React, for every DOM object, there is a corresponding “virtual DOM object.”

 

source: codeacademy.com

Why do you need virtual DOM?

While this is simple enough, once you start performing continuous mutations, more complexity arises. This is why the virtual DOM was created - to allow you to write declarative content (like the string in the innerHTML example) while harnessing performance by making only pinpoint changes to the DOM.

 

source: dev.to

Virtual DOM Process

Once Virtual DOM contains all the updated changes, it is then compared with the Real DOM and the difference is calculated between them.

Once the difference is calculated the real DOM will update only the new components that have actually changed.This is called Reconciliation. Virtual DOM is faster and more effective than Real DOM  as it just focuses on the updated components instead of updating the entire DOM.

Virtual DOM (Fiber nodes) plays a major role in boosting the performance of the applications. 

Only those few objects are changed in the real DOM (or Mobile UI Views) that was the outcome of the comparison between the previous states and the new states. This feature made things move faster and also reduced cost.

 

 

JSX

JSX stands for JavaScripts XML

  • JSX allows us to write HTML in React or XML UI Components in REact Native. (source: w3schools.com)
  • a syntax extension of JavaScript which allows users to write React components.

 

One - Way Data Binding

In one-way data binding one of the following conditions can be followed. Component to View: Any change in component data would get reflected in the view. View to Component: Any change in View would get reflected in the component’s data. (source: geeksforgeeks.org)

One-way data binding will bind the data from the component to the view (DOM) or from view to the component. One-way data binding is unidirectional/one-way. You can only bind the data from component to the view or from view to the component. (source: pluralsight.com)

What is one-way binding?

The Angular framework uses a two-way binding approach that changes the model state automatically when any change is made in the UI element and vice versa. The React library uses a one-way approach. This approach allows the change in the UI elements only after a change is made in the model state. The two-way approach seems to be easier, but React’s one-way approach is more effective for projects with large amounts of coding.

Props & State

Props stands for properties.

It is a special keyword in React which is used for passing data from one component to another. Logically, components are just like JavaScript functions. They accept random inputs (called “props”) and return React elements which tell what should be displayed on the screen. (source:knowledgehut.com)

Props are used to pass data, whereas state is for managing data. Data from props is read-only, and cannot be modified by a component that is receiving it from outside.

State data can be modified by its own component, but is private (cannot be accessed from outside).(source: freecodecamp.org)

Difference between props and state:

State

The state is a built-in React object that is used to contain data or information about the component. A component's state can change over time; whenever it changes, the component re-renders.

 

//Class component
class App extends React.Component {
	constructor() {
    	this.state = {
        counter: 1
        }
    }
}
//Function component
const App = () => {
	const [counter, setCounter] = useState(0)
}

source:https://www.simplilearn.com/tutorials/reactjs-tutorial/reactjs-state

State

Because of this nature of React internal state it must not be modified straight forward. Instead of that we use special method to not only change the state but cause the rerendering accordingly.

//Class component
class App extends React.Component {
	constructor() {
    	this.state = { counter: 1 }
    }
    
    change() {
    	// this.state = 2 – WRONG!
    	this.setState({counter: 2})
    }
    ...
}
//Function component
const App = () => {
	const [counter, setCounter] = useState(0)

	const change = () => {
		// counter = 2 WRONG!
    	setCounter(2)
    }
}

Data Flow in React 

What is unidirectional data flow in React?

Unidirectional data flow describes a one-way data flow where the data can move in only one pathway when being transferred between different parts of the program.

React, a Javascript library, uses unidirectional data flow. The data from the parent is known as props. You can only transfer data from parent to child and not vice versa.This means that the child components cannot update or modify the data on their own, making sure that a clean data flow architecture is followed. This also means that you can control the data flow better.

(source: Sheza Munir educative.io)

(source: Sheza Munir educative.io)

Effect of state changes

In React, each state is owned by one component. Due to the unidirectional flow, the changes made on the state of the component will only affect the children and not the parents or siblings.

Advantages of unidirectional data flow

There are many advantages of unidirectional data flow, some of which are listed below:

  • Debugging One-way data flow makes debugging much easier. When the developer knows where the data is coming from and where it is going, they can dry run (or use tools) to find the problems more efficiently.
  • Better control Having data flow in one direction makes the program less prone to errors and gives the developer more control.
  • Efficiency As the used libraries are wary of the limitations and specifications of the unidirectional flow, extra resources are not wasted, leading to an efficient process.

 

source: Sheza Munir educative.io

React Components

What are components?

 

Components are independent and reusable bits of code. They serve the same purpose as JavaScript functions, but work in isolation and return HTML/XML (JSX). Components come in two types, Class components and Function components.

 

As for now (2025) class components are rarely used. Prior to version 16.8 they were the only way to use component internal state. Since that version hooks has been present and thanks to them we can do without class.

 

How to create a component

 

  1. Class
  2. Function
  3. Function Expression
  4. Arrow function

 

What is a Class Component?

Class Component

A class component must include the extends React.Component statement. This statement creates an inheritance to React.Component, and gives your component access to React.Component’s functions.

 

import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';

class Greeting extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>Hello from a Class Component!</Text>
      </View>
    );
  }
}

What is a Functional Component?

A Function component also returns HTML, and behaves much the same way as a Class component, but Function components can be written using much less code, are easier to understand.

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const WelcomeMessage = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Welcome to React Native!</Text>
    </View>
  );
};

Demystifying components?

Let's try to demystify components a bit. In JavaScript, we use functions to create objects. Class syntax is just a syntactical sugar build on top of functions. 

function Person(name) {
	this.name = name
}

const me = new Person("Martin")
class Person {
    constructor(name){
        this.name = name
    }
}

const me = new Person("Marcin")

Demystifying components?

So components simply creates html nodes as objects. Under the hood, we have a well known object instantiation. 

function Person({name}) {
	this.name = name
}

//const me = new Person("Martin")
<Person name="Marcin" />
class Person {
	constructor(name){
		this.name = name
    }
}

//const me = new Person("Marcin")
<Person name="Marcin" />

What is instantiate object in JavaScript?

Instantiation refers to the creation of an object. Following that, instantiation patterns refer to the myriad ways to create instances of objects.

source: https://dev.to/mconner89/a-quick-guide-to-instantiation-in-javascript-6n

The this problem in JS

The this problem in JS

Arrow functions, introduced in ECMAScript 6 (ES6), provide a concise way to write function expressions in JavaScript. They are syntactically shorter than traditional function expressions and come with some differences in behavior, particularly with the this keyword.

The this problem in JS

One of the most significant differences is that arrow functions do not have their own this context. Instead, they inherit this from the surrounding non-arrow function. This is called lexical scoping.

Reconcilliation – how component rerenders

Let's introduce some terminology
 

1. Mounting 

2. Unmounting 

3. Render 

4. Rerender

Mounting

Mounting a component in the context of React refers to the process of integrating a component into the DOM (Document Object Model) for the first time. When a component is mounted, the following events occur:

  1. Initialization: The component is initialized, meaning its constructor is called (if it is a class component), and the initial state and props are set up.

  2. Lifecycle Methods:

    • For class components, the componentDidMount lifecycle method is called. This method is often used for tasks like fetching data from an API, setting up subscriptions, or any initialization that requires a DOM node.
    • For functional components using hooks, the useEffect hook with an empty dependency array [] acts similarly to componentDidMount and runs only once after the component is mounted.
  3. Rendering: The component's render method is called (for class components) or the function body is executed (for functional components), producing React elements which describe what should be displayed on the screen.

  4. Updating the DOM: React takes the elements returned from the render method and updates the DOM to match these elements. This is where the component gets visually displayed to the user.

Unmounting

Unmounting a component in React refers to the process of removing a component from the DOM. When a component is unmounted, it is completely removed from the DOM and its lifecycle comes to an end. This process is important for cleaning up resources and avoiding memory leaks.

Lifecycle Method for Unmounting

In class components, the componentWillUnmount lifecycle method is called just before a component is removed from the DOM. This method can be used to perform any necessary cleanup, such as invalidating timers, canceling network requests, or cleaning up subscriptions.

In functional components, the cleanup logic is handled within the useEffect hook by returning a cleanup function. This function is executed when the component is unmounted.

Rendering

Rendering a component in React refers to the process of generating the DOM elements that correspond to the component's structure and displaying them on the screen. This process can occur for the first time when a component is mounted or repeatedly when the component's state or props change, causing updates.

Initial Rendering

When a component is initially rendered, React:

  1. Calls the Render Method: For class components, React calls the render method. For functional components, React simply executes the component function.
  2. Creates React Elements: The render method or function returns React elements, which are plain JavaScript objects representing the structure of the UI.
  3. Updates the DOM: React takes these elements and translates them into actual DOM nodes, updating the DOM to match the elements.

Rerendering

Re-Rendering

Re-rendering occurs when a component's state or props change. This triggers a new render cycle, where React:

  1. Detects Changes: React detects changes in the component's state or props.
  2. Calls the Render Method Again: For class components, React calls the render method again. For functional components, it re-executes the function.
  3. Compares with Previous Output: React uses a diffing algorithm (Reconciliation) to compare the new React elements with the previous ones.
  4. Updates the DOM Efficiently: React updates only the parts of the DOM that have changed, minimizing the number of actual DOM operations.

Rerendering

React Keys

In React, keys are special attributes you need to include when creating lists of elements. They help React identify which items have changed, are added, or are removed. This is crucial for efficiently updating the user interface.

Why Are Keys Important?

  1. Performance Optimization: Keys help React perform reconciliation efficiently by providing a way to identify which items in a list have changed, allowing React to minimize the number of DOM manipulations.
  2. Stability: Keys ensure that components maintain their state and identity across re-renders. Without keys, React may re-use the wrong component instances, leading to bugs and inconsistent UI.

React Keys

In React, keys are special attributes you need to include when creating lists of elements. They help React identify which items have changed, are added, or are removed. This is crucial for efficiently updating the user interface.

import { View, Text } from 'react-native';

const items = ['Apple', 'Banana', 'Cherry'];

export default function MyComponent() {
  return (
    <View>
      {items.map((item, index) => (
        <Text key={item}>{item}</Text>
      ))}
    </View>
  );
}

React Keys

How to Use Keys

Keys should be given to the elements inside an array to give the elements a stable identity. The best practice is to use a unique identifier from your data as the key. If your data doesn't have a unique identifier, using the array index as a key is the last resort.

import React from 'react';

const ListWithKeys = () => {
  const items = ['Item 1', 'Item 2', 'Item 3'];
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
};

export default ListWithKeys;

React Hooks

 

  • Hooks let you use state and other React features without writing a class.
  • Hooks are a new addition in React 16.8 react.js
  • Hooks allow us to hook into React features such as state and lifecycle methods. 

 

Hook Rules

There are 3 rules for hooks:

  • Hooks can only be called inside React function components.
  • Hooks can only be called at the top level of a component.
  • Hooks cannot be conditional.

Note: Hooks will not work in React class components.

Read this for more info about Hooks⬇️

 

useState

useState is the most basic React Hook. It's used to assign the state to the component and to optionally change the state.

 

The signature of the hook is a tuple where the first element is the state itself and the second element is the setter function.

const [count, setCount] = useState(0);

Each state has its own initial value. It's null by default but we may assign any initial value (It's 0 in the example above).

useState

import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

const Example = () => {
  const [count, setCount] = useState(0);

  return (
    <View style={styles.container}>
      <Text style={styles.text}>You clicked {count} times</Text>
      <Button title="Click me" onPress={() => setCount(count + 1)} />
    </View>
  );
};

export default Example;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 18,
    marginBottom: 10,
  },
});

Let's keep in mind that each state change makes the component render (return again).

useState

import React, { useState } from 'react';
import { View, Text, Button, Pressable, StyleSheet } from 'react-native';

const Example = () => {
  const [count, setCount] = useState(0);
  const [color, setColor] = useState('blue');

  const toggleColor = () => {
    setColor(prev => (prev === 'blue' ? 'red' : 'blue'));
  };

  return (
    <View style={styles.container}>
      <Text style={styles.text}>You clicked {count} times</Text>

      <Button title="Click me" onPress={() => setCount(count + 1)} />

      <Pressable
        onPress={toggleColor}
        style={[styles.customButton, { backgroundColor: color }]}
      >
        <Text style={styles.buttonText}>Click me</Text>
      </Pressable>
    </View>
  );
};

Feel free to add as many states as you want.

useState

import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

const Example = () => {
  const [count, setCount] = useState({ count: 0 });
  const [color, setColor] = useState('blue');

  return (
    <View style={styles.container}>
      <Text style={styles.text}>You clicked {count.count} times</Text>

      <Button
        title="Click me"
        onPress={() =>
          setCount(prev => ({ count: prev.count + 1 }))
        }
      />
    </View>
  );
};

export default Example;

You may as well create a state which value is scalar – object or array.

useState

//When we don't need the previous value
setCount(10);

//When we want to update state base on it's actual value
setCount(prev => ({count: prev.count + 1}));

Setter function has exactly one argument. It can be function or any other value. In case it's a function you may safely reference the actual state and modify it.

useEffect

import React, { useState, useEffect } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

const Example = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // In React Native, there's no document.title
    // You can log the change or use it for something else
    console.log(`You clicked ${count} times`);
  }, [count]); // dependency array to avoid running on every render

  return (
    <View style={styles.container}>
      <Text style={styles.text}>You clicked {count} times</Text>
      <Button title="Click me" onPress={() => setCount(count + 1)} />
    </View>
  );
};

export default Example;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 18,
    marginBottom: 12,
  },
});

useEffect hook allows you to perform side effects in your components. Some examples of side effects are: fetching data, directly updating the DOM, and timers. useEffect accepts two arguments.  

useEffect

First argument of the hook is always a callback function. It's says whenever anything changes in the component (props or state) function shall execute.

useEffect

  useEffect(() => {
    const interval = setInterval(() => console.log("I'm still alive"), 1000);
    
    return () => clearInterval(interval)
  });

In numerous cases you would like to "clean up" after your component. In the example below we have an interval.

 

Imagine that your component disappeared from UI, the interval would still be functioning. To prevent that we can clean up any intervals, unresolved api call etc. on return. We do so returning the callback with cleanups from the hook.

 

useEffect

  useEffect(() => {
    console.log("I'm reacting to first render")
  }, []);
  
  useEffect(() => {
    console.log("I'm reacting to a specific change")
  }, [anyValue]);

As for now our hook has reacted to any state or props change. But we can easily make it react to any particular state or props change. We need to add a second parameter which is an array of values that the hook is supposed to observe. If the array is empty it means that the callback will work just once after the first render.

 

useEffect

Be careful with useEffect hook. It can be tricky and if you overdo it, it will lead to callback hell (hard to follow and debug sequence of state changes).

 

 

 

 Callback Hell is essentially nested callbacks stacked below one another forming a pyramid structure. Every callback depends/waits for the previous callback, thereby making a pyramid structure that affects the readability and maintainability of the code.

 

source:https://www.geeksforgeeks.org/what-to-understand-callback/

useMemo

useMemo allows us to cache any heavy computations in our components. Each function inside your component would execute on each render. 

 

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

In the example above computeExpensiveValue would execute only if any of a or b changes.

React.memo()

When it comes to memoization, there is one more method worth mentioning. When parent components render all, its children render accordingly even if nothing changes actually inside it. To cache the component and prevent rendering, whenever parent component renders, we may memoize it. 

const MyComponent = React.memo(function MyComponent(props) {
  /* render using props */
} /* optional comaparison function (prevProps, nextProps) => { ... } */);

In react memo, it will render only if any of its props changes. The comparison is shallow in this case so we might need a second parameter to compare props.

React.memo()

Do not overuse React.memo – it might me tempting to use it everywhere but comparing props is a procedure that consumes resources as well. Consider if memoization is worth this expense. In numerous cases, memoization would harm your performance not increase it. 

useCallback

useCallback is one of the toughest to understand. In fact, on the Internet there are plenty of misleading information about it. 

Function is just an object (like everything in JavaScript under the hood). So, while comparing props (for example in React.memo process) any callback sent to the children components would be a different prop and would cause rerendering.

 

 

{} === {} // Falsy

useCallback

Thanks to useCallback the callback function will not be recreated on each render. The same as with useMemo it takes the second parameter with the list of dependencies. When those dependencies changes the function is recreated accordingly.

...
const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

return <Child callback={memoizedCallback} />
...

function Child = React.memo(({callback}) => {
...
})

useRef

With useRef hook we can reference the actual DOM element as we would have done this with methods like document.querySelector. This simply means that ref stays intact of the full component life-cycle and it is mutable.

The common use case is when you want to reference DOM elements imperatively.

useRef

import React, { useRef } from 'react';
import { View, TextInput, Button, StyleSheet } from 'react-native';

const TextInputWithFocusButton = () => {
  const inputRef = useRef(null);

  const onButtonClick = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        ref={inputRef}
        style={styles.input}
        placeholder="Type something..."
      />
      <Button title="Focus the input" onPress={onButtonClick} />
    </View>
  );
};

export default TextInputWithFocusButton;

useRef

To access current ref value  we use its current attribute.

import React, { useRef } from 'react';
import { View, TextInput, Button, StyleSheet } from 'react-native';

const TextInputWithFocusButton = () => {
  const inputRef = useRef(null);

  const onButtonClick = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        ref={inputRef}
        style={styles.input}
        placeholder="Enter text"
      />
      <Button title="Focus the input" onPress={onButtonClick} />
    </View>
  );
};

export default TextInputWithFocusButton;

useRef

The second important function of refs is its ability to expose DOM elements to third party libraries inside react components. As you know React operates with the boundaries of virtual DOM but most third party libraries don't. One of the most popular examples is the usage of Google Maps in React Component.

const map = new google.maps.Map(
    document.getElementById("map")
    {
      zoom: 4,
      center: uluru,
    }
  );

You may as well use event jQuery with ref. Another example: animations with GSAP, sliders ect.

useRef

There is a rare occasion when you might need to listen to the process of attaching and detaching ref to an element in a child component. It can be useful in animations.

 

In this case you can use the so-called callback ref.

 

 

 

 

https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node

https://codesandbox.io/s/818zzk8m78

forwardRef

There is an infrequent occurrence when we might need to access the ref of a child component from the parent perspective. It happens with animations and when it comes to small reusable components like button.

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// Usage
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>

useImperativeHandle

useImperativeHandle when you want to expose methods of a child component to be callable by the parent component. This is an advanced use case and is typically needed when you need to control the behavior of child components imperatively rather than declaratively.

How to Use useImperativeHandle

  1. Create a Ref in the Parent Component: First, create a ref in the parent component using React.createRef or useRef.

  2. Pass the Ref to the Child Component: Pass the ref to the child component where you want to expose methods.

  3. Use useImperativeHandle in the Child Component: Use the useImperativeHandle hook in the child component to specify which methods or properties you want to expose.

useImperativeHandle

import React, { forwardRef, useImperativeHandle, useRef } from 'react';
import { View, TextInput } from 'react-native';

const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef();

  // Expose focusInput method to parent via ref
  useImperativeHandle(ref, () => ({
    focusInput: () => {
      inputRef.current && inputRef.current.focus();
    },
  }));

  return (
    <View>
      <TextInput
        ref={inputRef}
        placeholder="Type something..."
        style={{ borderWidth: 1, padding: 8, borderRadius: 4 }}
      />
    </View>
  );
});

export default ChildComponent;

useImperativeHandle

import React, { useRef } from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
import ChildComponent from './ChildComponent';

export default function ParentComponent() {
  const childRef = useRef();

  const handleClick = () => {
    if (childRef.current) {
      childRef.current.focusInput();
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <ChildComponent ref={childRef} />
      <TouchableOpacity
        onPress={handleClick}
        style={{
          marginTop: 16,
          backgroundColor: '#007AFF',
          padding: 12,
          borderRadius: 6,
          alignItems: 'center',
        }}
      >
        <Text style={{ color: 'white' }}>Focus Input</Text>
      </TouchableOpacity>
    </View>
  );
}

useReducer

Another pretty useful hook is useReducer. Not that popular but definitely worth mentioning. Basically, it's the same as useState but it allows us to deal with complicated and nested states. It also allows us to carry out complicated mutations of the state.

const [state, dispatch] = useReducer(reducer, initialArg, init);
  1. reducer – a function with two arguments a state and an action.
  2. initial state
  3. optional function - is to initiate state in a lazy manner.

useReducer

The most important part is the reducer function. We may conduct complicated mutations of the state there.

An action must have its type and optionally a set of data attached to the action. It's conventionally named payload. In reducer we check the type either with a switch statement or with an if statement and we mutate it accordingly.

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + action.payload};
    case 'decrement':
      return {count: state.count - action.payload};
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}

The concept of reducer function is widely used in Redux as well.

Concurent Features

React team were working many years on a feature that would allow asynchronous rendering. There are some evloutions of that process.

Async Mode

Concurrent Rendering

Concurrent Mode

Concurrent Features
 

Concurent Features

It’s called Concurrent because React can work on multiple versions of your UI at the same time in a cooperative, interruptible way, but all of that work still runs on the single JavaScript thread in the browser.

Here’s the breakdown:

1. What "Concurrent" means in React

  • Normally, React rendering is synchronous — once it starts rendering, it goes until it’s done.

  • In Concurrent Mode (or modern "Concurrent Features" in React 18), React can pause, resume, abandon, or restart rendering work.

  • This gives React time to respond to higher-priority updates (like user typing) without freezing the UI.

 

 

useDefferedValue

In React, useDeferredValue is a hook introduced in React 18. It is used to defer the computation of a value and to render the updated value asynchronously. This can help to improve the user experience by avoiding unnecessary blocking of the main thread for expensive computations or rendering operations, making the UI feel more responsive.

import { useState, useDeferredValue } from 'react';

function SearchPage() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  // ...
}

useTransition

 

import React, { useState, useTransition } from 'react';
import { View, TextInput, FlatList, Text } from 'react-native';

export default function App() {
  const [query, setQuery] = useState('');
  const [list, setList] = useState([]);
  const [isPending, startTransition] = useTransition();

  const data = [/* ...lots of data... */];

  const handleChange = (text) => {
    setQuery(text);
    startTransition(() => {
      const filtered = data.filter(item => item.includes(text));
      setList(filtered);
    });
  };

  return (
    <View>
      <TextInput value={query} onChangeText={handleChange} />
      {isPending && <Text>Loading...</Text>}
      <FlatList
        data={list}
        renderItem={({ item }) => <Text>{item}</Text>}
        keyExtractor={item => item}
      />
    </View>
  );
}

useTransition in React Native

What is it?

  • useTransition is a React hook that helps you manage concurrent UI updates—making non-urgent updates feel less “janky” by keeping the app responsive.

  • It lets you prioritize urgent updates (like typing) over less urgent ones (like rendering a large list or filtering results).

useLayoutEffect

 

useLayoutEffect is a hook in React that allows you to run side effects in your components, similar to useEffect. However, there are important differences in when these effects are executed. Understanding these differences can help you optimize your React applications and prevent potential UI issues.

Key Differences Between useEffect and useLayoutEffect

useLayoutEffect

 

  • Timing of Execution:

    • useEffect: Runs asynchronously after the browser has painted the screen. This means it does not block the visual rendering of the component.
    • useLayoutEffect: Runs synchronously after all DOM mutations but before the browser has a chance to paint. This means it blocks the painting of the component until the effect has run, ensuring that any DOM changes are made before the paint.
  • Use Cases:

    • useEffect: Suitable for side effects that do not affect the layout of the component, such as data fetching, subscriptions, or logging.
    • useLayoutEffect: Ideal for side effects that require reading or writing layout information, such as measurements, mutations that should happen before the paint, and updating refs.

useLayoutEffect

 

When Should You Use useLayoutEffect in React Native?

  • When you need to measure or update the UI immediately after changes, but before the user sees anything.

  • Example scenarios:

    • Measuring component size or position right after render (to scroll, animate, etc.).

    • Synchronous animations that must happen before the UI appears.

    • Making layout-based calculations.

import React, { useRef, useLayoutEffect } from 'react';
import { ScrollView, Text } from 'react-native';

export default function Chat({ messages }) {
  const scrollViewRef = useRef();

  useLayoutEffect(() => {
    // Scroll to the end *before* painting, for a smoother experience
    if (scrollViewRef.current) {
      scrollViewRef.current.scrollToEnd({ animated: false });
    }
  }, [messages]);

  return (
    <ScrollView ref={scrollViewRef}>
      {messages.map((msg, i) => (
        <Text key={i}>{msg}</Text>
      ))}
    </ScrollView>
  );
}
function AComponent(children) {
  const targetRef = React.useRef(null)

  useLayoutEffect(() => {
    targetRef.current?.measure((x, y, width, height, pageX, pageY) => {
      //do something with the measurements
    });
  }, [ /* add dependencies here */]);

  return (
    <View ref={targetRef}>
     {children}
    <View />
  );
}

You would use useLayoutEffect to measure layout

useId

 

It's just a simple helper hook that gives us a uniqe id consistent between renders

React 19

 

React 19, released on December 5, 2024, introduces several significant features and improvements to enhance the development experience and application performance. Here's an overview of what's new:

 

Actions

React 19 introduces "Actions," allowing developers to use asynchronous functions within transitions to handle pending states, errors, forms, and optimistic updates automatically. This simplifies the management of asynchronous operations in React applications.

 

 

 

React 19

 

New Hooks

Several new hooks have been added to streamline state management and form handling:

  • useActionState: Simplifies managing form states and submissions by capturing form input data, handling validation, and error states, reducing the need for custom state management logic

  • useFormStatus: Allows nested child components to access information about the form they are part of, such as pending status, data, method, and action.

  • useOptimistic: Enables optimistic updates by allowing components to render a temporary state while awaiting the result of an asynchronous operation, enhancing user experience by providing immediate feedback.

     

React 19

 

Server Components

React 19 introduces Server Components, which are stateless components that run on the server. These components can access the data layer directly without needing to interact with an API, reducing the amount of JavaScript sent to the client and improving initial page load times.

 

Server Actions

Building upon Server Components, Server Actions allow Client Components to call asynchronous functions executed on the server. This enables functionalities like reading the file system or making direct database calls, removing the need for creating bespoke API endpoints for the UI.

 

React 19

 

New API: use

The new use API provides a flexible method to read values from resources such as promises or context. Unlike traditional hooks, use can be called conditionally and integrates seamlessly with Suspense and error boundaries.

 

Improved Asset Loading

React 19 enhances support for stylesheets and asynchronous scripts, allowing developers to render them anywhere in the component tree without managing their relocation or deduplication. This ensures that styles and scripts are loaded efficiently, improving application performance.

 

 

React 19

 

Better Error Reporting

Error handling has been improved to remove duplication and provide clearer messages. React 19 logs a single error with all relevant information, helping developers quickly identify and fix issues. Additionally, two new root options have been added: onCaughtError and onUncaughtError, providing better clarity on why an error is happening.

 

 

 

useActionState

 

This hook allows to handle form submission and all pending statuses and error reportings

 

 

 

const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);

useActionState

 

This hook allows to handle form submission and all pending statuses and error reportings

 

 

 

import { useActionState } from 'react';
import { action } from './actions.js';

function MyComponent() {
  const [state, formAction] = useActionState(action, null);
  // ...
  return (
    <form action={formAction}>
      {/* ... */}
    </form>
  );
}

useFormStatus

 

React 19 allows to automatically access the state of a form in child components without props drilling

 

 

 

import { useFormStatus } from "react-dom";
import action from './actions';

function Submit() {
  const status = useFormStatus();
  return <button disabled={status.pending}>Submit</button>
}

export default function App() {
  return (
    <form action={action}>
      <Submit />
    </form>
  );
}

Custom Hooks

 

A custom Hook doesn’t need to have a specific signature. We can decide what it takes as arguments, and what, if anything, it should return. In other words, it’s just like a normal function. Its name should always start with use so that you can tell at a glance that the rules of Hooks apply to it.

 

 

 

Example:

 

The purpose of our useFriendStatus Hook is to subscribe us to a friend’s status. This is why it takes friendID as an argument, and returns whether this friend is online:

 

 

Custom Hooks offer the flexibility of sharing logic that wasn’t possible in React components before. You can write custom Hooks that cover a wide range of use cases like form handling, animation, declarative subscriptions, timers, and probably many more we haven’t considered. What’s more, you can build Hooks that are just as easy to use as React’s built-in features.

Events with forms

  • each input keeps its value in the React state
  • each input has its onChange method

The End of React.js Course.

See you on the next one! 😉 ➡️

React Native Day 1

By noinputsignal

React Native Day 1

  • 4