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.
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?
● Environment Setup
● First App: Hello World
● Core React Concepts (Recap)
● Hands-On
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 :)
React Native is an open-source framework for building mobile applications.
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
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
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
Hybrid apps combine web technologies with native features, while RN uses native components.
React Native offers near-native performance compared to hybrid and web apps.
Strong community support with numerous libraries and resources available.
Continued growth and improvements expected in 2025 and beyond.
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.
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.
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.
Xamarin in other hand is mostly code generator (especially on IOS)
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
So from the perspective of RN the main goal is to communicate and manipulate bot UI Components and Native (Turbo) Modules.
In this model, communication between JavaScript and native code (Android/iOS) happens through a Bridge.
You call a method from JS, like:
NativeModules.ToastModule.show("Hello", ToastModule.SHORT);The function call, module name, method name, and arguments are packaged into a JSON message.
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.
Native code (Java/Swift/etc.) receives the message.
It maps it to a native method and executes the corresponding function.
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) ]| 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 |
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
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 |
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
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
https://reactnative.dev/architecture/render-pipeline
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).
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.
Replaces NativeModules
Native modules are now:
Lazy-loaded
Accessed via JSI
More efficient & modular
Enables fast access to device features (camera, sensors, storage)
Developers define native module interfaces in TypeScript or Flow
Codegen:
Generates native bindings automatically (iOS & Android)
Enforces type safety
Reduces manual boilerplate
Here we define the threading model and provide some examples to illustrate thread usage of the render pipeline.
The renderer uses two different threads:
https://reactnative.dev/architecture/threading-model
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 |
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:
Managed Workflow
No native code
Use only supported Expo SDK features
Easiest to maintain
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:
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
When to Use Expo:
When you need to build quickly
When native customization is not required
When working with small teams or solo
npm install -g expo-cli # Optional: Global install
npx create-expo-app MyApp --template
cd MyApp
npx expo startA 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.
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.
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
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
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
JSX
One Way Data Binding
Shadow Tree (virtual dom)
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.
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 |
Stack
➡️ 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
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
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
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
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 stands for JavaScripts XML
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 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)
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)
}
}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:
source: Sheza Munir educative.io
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
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>
);
}
}
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>
);
};
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")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
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.
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.
Let's introduce some terminology
1. Mounting
2. Unmounting
3. Render
4. Rerender
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:
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.
Lifecycle Methods:
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.useEffect hook with an empty dependency array [] acts similarly to componentDidMount and runs only once after the component is mounted.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.
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 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.
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 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.
When a component is initially rendered, React:
render method. For functional components, React simply executes the component function.render method or function returns React elements, which are plain JavaScript objects representing the structure of the UI.Re-rendering occurs when a component's state or props change. This triggers a new render cycle, where React:
render method again. For functional components, it re-executes the function.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.
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>
);
}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;
source:w3schools.com
Hook Rules
There are 3 rules for hooks:
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.
{} === {} // FalsyuseCallback
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.
useImperativeHandleCreate a Ref in the Parent Component: First, create a ref in the parent component using React.createRef or useRef.
Pass the Ref to the Child Component: Pass the ref to the child component where you want to expose methods.
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);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:
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 NativeuseTransition 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.
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
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>
);
}
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.
source: Read ⬇️ https://reactjs.org/docs/hooks-custom.html
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