Uvod u Novu Arhitekturu React Nativea
React Native prešao je prilično dug put od 2015. godine. Ono što je krenulo kao pomalo eksperimentalni okvir za izradu mobilnih aplikacija u JavaScriptu danas je ozbiljna platforma koja pokreće tisuće aplikacija — od malih startupova do kompanija poput Mete, Shopifyja i Microsofta. Ali jedna od najbitnijih promjena u cijeloj povijesti React Nativea dogodila se upravo u posljednje dvije godine: potpuna transformacija unutarnje arhitekture.
Dakle, o čemu se zapravo radi?
Nova Arhitektura React Nativea (eng. New Architecture) predstavlja fundamentalnu promjenu u načinu na koji JavaScript komunicira s nativnim kodom. Umjesto starog asinkronog mosta (eng. bridge), koji je godinama bio usko grlo za performanse, nova arhitektura uvodi izravnu, sinkronu komunikaciju putem JSI (JavaScript Interface), novi sustav renderiranja nazvan Fabric, te modernizirane nativne module — TurboModules. Od verzije React Native 0.82, nova arhitektura je jedini podržani način rada, a u Expo SDK 55 (siječanj 2026.) više se ne može ni isključiti.
U ovom vodiču detaljno ćemo proći sve komponente nove arhitekture, objasniti kako funkcioniraju, pokazati praktične primjere koda i pružiti korak-po-korak upute za migraciju postojećih projekata. Bilo da ste iskusni React Native developer ili tek počinjete, razumijevanje nove arhitekture je ključno za razvoj performantnih mobilnih aplikacija u 2026. godini.
Problemi stare arhitekture: Zašto je most bio usko grlo
Da bismo potpuno shvatili prednosti nove arhitekture, moramo najprije razumjeti ograničenja stare. Klasična React Native arhitektura temeljila se na tri glavne niti:
- JavaScript nit — izvršava JavaScript kod, upravlja poslovnom logikom i React stablom komponenata
- Nativna nit (Main/UI thread) — odgovorna za renderiranje nativnih UI komponenata i obradu korisničkih interakcija
- Shadow nit — izračunava raspored elemenata (layout) koristeći Yoga engine
Komunikacija između ovih niti odvijala se putem asinkronog mosta (bridge). Svaka poruka morala je proći serijalizaciju u JSON format, prijenos preko mosta, pa deserijalizaciju na drugoj strani. I tu su nastajali problemi:
- Latencija — Serijalizacija i deserijalizacija JSON podataka zahtijevala je dodatno vrijeme, posebno kod velikih struktura podataka
- Asinkronost — Budući da je komunikacija bila asinkrona, nije bilo moguće sinkrono pristupiti nativnim resursima iz JavaScripta
- Zagušenje — Pri intenzivnom korištenju (npr. brze animacije, česte promjene layouta), most bi se jednostavno zagušio porukama, što je uzrokovalo padove broja okvira (frame drops)
- Učitavanje svih modula pri pokretanju — Svi nativni moduli inicijalizirali su se prilikom pokretanja aplikacije, čak i oni koji se nikada neće koristiti. To je nepotrebno produljivalo vrijeme pokretanja
Ovi problemi su bili posebno vidljivi na uređajima slabijih performansi, gdje je zagušenje mosta moglo dovesti do primjetnog zastajkivanja sučelja i sporih animacija. Iskreno, tko je ikada radio s React Nativeom na starijem Android uređaju, zna koliko je to moglo biti frustrirajuće.
JSI: Temelj nove komunikacije
JavaScript Interface (JSI) je srce nove arhitekture. Radi se o laganom, niskoj razini sučelju napisanom u C++ koje omogućuje JavaScriptu izravno držanje referenci na C++ objekte — i obrnuto. To znači da JavaScript može pozivati nativne metode sinkrono, bez ikakve serijalizacije podataka u JSON.
Kako JSI funkcionira
JSI zamjenjuje stari most izravnim vezama između JavaScripta i nativnog koda. Umjesto slanja poruka kroz red čekanja, JavaScript sada može:
- Izravno pozivati C++ funkcije
- Držati reference na nativne objekte
- Pristupati nativnim podacima bez kopiranja (zero-copy)
- Koristiti sinkrone i asinkrone pozive prema potrebi
Evo pojednostavljenog prikaza razlike:
// Stari pristup (Bridge)
// JavaScript → JSON serijalizacija → Bridge → JSON deserijalizacija → Native
// Native → JSON serijalizacija → Bridge → JSON deserijalizacija → JavaScript
// Novi pristup (JSI)
// JavaScript ←→ JSI (C++) ←→ Native
// Izravna komunikacija, bez serijalizacije
JSI je također agnostičan prema JavaScript enginu — i to je zapravo jako bitno. React Native više nije vezan isključivo za JavaScriptCore. Može koristiti Hermes (koji je danas zadani engine), V8 ili bilo koji drugi JavaScript engine koji implementira JSI sučelje.
Prednosti JSI-ja u praksi
Praktične prednosti su prilično značajne:
- Brže animacije — Sinkrona komunikacija omogućuje glatke animacije na 60+ FPS bez zastajkivanja
- Brži pristup podacima — Nema više čekanja na serijalizaciju i deserijalizaciju
- Manji memorijski otisak — Zero-copy pristup podacima smanjuje korištenje memorije
- Fleksibilnost — Mogućnost korištenja različitih JavaScript enginea
TurboModules: Sljedeća generacija nativnih modula
TurboModules su nasljednici klasičnih NativeModules. Koriste JSI za izravnu komunikaciju s nativnim kodom i donose nekoliko ključnih poboljšanja koja stvarno utječu na performanse i razvojno iskustvo.
Ključne razlike od starih NativeModules
- Lijeno učitavanje (lazy loading) — TurboModules se inicijaliziraju tek kada ih aplikacija prvi put zatraži, umjesto pri pokretanju. To dramatično smanjuje vrijeme pokretanja aplikacije
- Tipski sigurni — Koriste Codegen za generiranje nativnog koda iz TypeScript/Flow specifikacija, osiguravajući tipsku sigurnost na obje strane
- Sinkroni pozivi — Mogu izvoditi sinkrone pozive kada je to potrebno, zahvaljujući JSI-ju
- Bolje upravljanje memorijom — Dijele memoriju između JavaScripta i nativnog koda bez kopiranja
Kreiranje TurboModula: Korak po korak
Ajmo proći kroz kreiranje TurboModula. Sve započinje definiranjem TypeScript specifikacije — Codegen koristi tu specifikaciju za automatsko generiranje nativnog koda. Datoteka mora pratiti konvenciju imenovanja Native{ImeModula}.ts.
Korak 1: Definiranje TypeScript specifikacije
// specs/NativeDeviceInfo.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
getDeviceModel(): Promise<string>;
getBatteryLevel(): Promise<number>;
getStorageInfo(): Promise<{
totalSpace: number;
freeSpace: number;
}>;
isCharging(): boolean; // sinkroni poziv
}
export default TurboModuleRegistry.getEnforcing<Spec>(
'NativeDeviceInfo'
);
Korak 2: Konfiguriranje Codegen-a
U package.json dodajte konfiguraciju:
{
"codegenConfig": {
"name": "NativeDeviceInfoSpec",
"type": "modules",
"jsSrcsDir": "specs",
"android": {
"javaPackageName": "com.myapp.deviceinfo"
}
}
}
Korak 3: Implementacija na iOS-u (Objective-C++)
// ios/NativeDeviceInfo.mm
#import <NativeDeviceInfoSpec/NativeDeviceInfoSpec.h>
#import <UIKit/UIKit.h>
@interface NativeDeviceInfo : NSObject <NativeDeviceInfoSpec>
@end
@implementation NativeDeviceInfo
RCT_EXPORT_MODULE()
- (void)getDeviceModel:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
resolve([[UIDevice currentDevice] model]);
}
- (void)getBatteryLevel:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
float level = [UIDevice currentDevice].batteryLevel;
resolve(@(level * 100));
}
- (NSNumber *)isCharging {
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
UIDeviceBatteryState state = [UIDevice currentDevice].batteryState;
return @(state == UIDeviceBatteryStateCharging);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params {
return std::make_shared<facebook::react::NativeDeviceInfoSpecJSI>(
params
);
}
@end
Korak 4: Korištenje u aplikaciji
// App.tsx
import NativeDeviceInfo from './specs/NativeDeviceInfo';
async function prikaziInfoUredaja() {
const model = await NativeDeviceInfo.getDeviceModel();
const baterija = await NativeDeviceInfo.getBatteryLevel();
const puni = NativeDeviceInfo.isCharging(); // sinkroni poziv!
console.log(`Model: ${model}`);
console.log(`Baterija: ${baterija}%`);
console.log(`Punjenje: ${puni ? 'Da' : 'Ne'}`);
}
// Korištenje u React komponenti
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
function DeviceInfoScreen() {
const [info, setInfo] = useState<{
model: string;
battery: number;
} | null>(null);
useEffect(() => {
async function ucitaj() {
const model = await NativeDeviceInfo.getDeviceModel();
const battery = await NativeDeviceInfo.getBatteryLevel();
setInfo({ model, battery });
}
ucitaj();
}, []);
if (!info) return <Text>Učitavanje...</Text>;
return (
<View>
<Text>Uređaj: {info.model}</Text>
<Text>Baterija: {info.battery}%</Text>
</View>
);
}
Fabric: Novi sustav renderiranja
Fabric je potpuno novi sustav renderiranja koji zamjenjuje stari UIManager. Dok je stari sustav koristio most za komunikaciju između React stabla i nativnih pogleda, Fabric koristi JSI za izravnu manipulaciju nativnim komponentama iz C++ koda. To je, jednostavno rečeno, ogromna razlika u praksi.
Ključne karakteristike Fabrica
- Konkurentno renderiranje — Fabric podržava Concurrent React značajke poput
Suspense,Transitionsi automatskog grupiranja ažuriranja (batching), što omogućuje responzivnije korisničko sučelje - Dijeljeni C++ jezgreni kod — Logika renderiranja dijeli se između iOS-a i Androida, smanjujući nedosljednosti među platformama
- Sinkroni pristup layoutu — Moguće je sinkrono čitati raspored elemenata, što je ključno za glatke animacije i geste
- Poboljšana tipska sigurnost — Codegen generira tipski siguran kod za Fabric komponente, smanjujući mogućnost runtime pogrešaka
Kreiranje Fabric Native komponente
Fabric komponente koriste sličan pristup kao TurboModules — započinjete s TypeScript specifikacijom.
Korak 1: TypeScript specifikacija za komponentu
// specs/ProgressBarNativeComponent.ts
import type { ViewProps } from 'react-native';
import type {
Float,
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
interface NativeProps extends ViewProps {
progress: Float; // Vrijednost napretka (0.0 - 1.0)
color?: string; // Boja trake
trackColor?: string; // Boja pozadine trake
animated?: WithDefault<boolean, true>; // Animirani prijelazi
thickness?: WithDefault<Int32, 4>; // Debljina trake u pikselima
}
export default codegenNativeComponent<NativeProps>(
'ProgressBarView'
);
Korak 2: Korištenje komponente u aplikaciji
import React, { useState, useEffect } from 'react';
import { View, Button, StyleSheet } from 'react-native';
import ProgressBarView from './specs/ProgressBarNativeComponent';
function DownloadScreen() {
const [progress, setProgress] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setProgress(prev => {
if (prev >= 1) {
clearInterval(interval);
return 1;
}
return prev + 0.01;
});
}, 100);
return () => clearInterval(interval);
}, []);
return (
<View style={styles.container}>
<ProgressBarView
progress={progress}
color="#4CAF50"
trackColor="#E0E0E0"
animated={true}
thickness={8}
style={styles.progressBar}
/>
<Button
title="Resetiraj"
onPress={() => setProgress(0)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
},
progressBar: {
height: 20,
width: '100%',
marginBottom: 20,
},
});
Bridgeless Mode: Potpuno uklanjanje mosta
Bridgeless Mode je posljednji korak u evoluciji nove arhitekture — i nekako najzadovoljavajući. Dok su TurboModules i Fabric već zaobišli most za većinu operacija, Bridgeless Mode potpuno uklanja sve preostale ovisnosti o starom mostu. To uključuje interne sustave poput upravljanja događajima i vremenskim intervalima koji su prethodno još uvijek koristili bridge.
Što se mijenja u Bridgeless modu
- Event sustav — Događaji (touch, scroll, keyboard) sada prolaze izravno kroz JSI umjesto kroz most
- Timer sustav —
setTimeout,setIntervalirequestAnimationFramekoriste nativne implementacije bez mosta - Modul registracija — Moduli se registriraju izravno u JSI runtime umjesto kroz stari bridge registry
- Error handling — Greške se propagiraju izravno, što omogućuje bolje stack trace poruke i brže debugiranje
Utjecaj na performanse
Prema testiranjima u produkcijskim okruženjima, Bridgeless Mode donosi zaista značajna poboljšanja:
- Time-To-Interactive (TTI) — smanjenje do 50% zahvaljujući eliminaciji overhead-a mosta i lijenom učitavanju modula
- Memorijsko korištenje — smanjenje za 10-20% jer nema potrebe za održavanjem struktura podataka vezanih uz most
- Glatkoća animacija — konzistentnih 60 FPS čak i na slabijim uređajima zahvaljujući sinkronoj komunikaciji
Codegen: Automatsko generiranje koda
Codegen je alat koji automatski generira nativni kod (C++, Objective-C++, Java) iz vaših TypeScript ili Flow specifikacija. Možete ga zamisliti kao ljepilo koje povezuje JavaScript tipove s nativnim implementacijama, osiguravajući tipsku sigurnost preko granica programskih jezika.
Kako Codegen funkcionira
Proces je relativno jednostavan:
- Definirate TypeScript sučelje za svoj modul ili komponentu
- Codegen analizira specifikaciju i identificira tipove, metode i svojstva
- Automatski generira nativni kod za iOS (Objective-C++) i Android (Java/Kotlin)
- Generirani kod uključuje tipski sigurne omotače, serijalizacijske metode i JNI/ObjC mostove
// Pokretanje Codegen-a
// Za Expo projekte - automatski se pokreće pri gradnji
npx expo prebuild
// Za bare React Native projekte
npx react-native codegen
// Konfiguracija u package.json
{
"codegenConfig": {
"name": "AppSpecs",
"type": "all",
"jsSrcsDir": "specs",
"android": {
"javaPackageName": "com.myapp"
}
}
}
Podržani tipovi u Codegen-u
Codegen podržava širok raspon TypeScript tipova koji se mapiraju na odgovarajuće nativne tipove:
string→NSString(iOS) /String(Android)number→doublena obje platformeboolean→BOOL(iOS) /boolean(Android)Float/Int32→ specifični numerički tipoviPromise<T>→ asinkroni pozivi s resolve/reject- Objekti i nizovi → odgovarajuće nativne strukture
WithDefault<T, defaultValue>→ svojstva sa zadanim vrijednostima
Hermes v1: Optimizirani JavaScript engine
Hermes je JavaScript engine koji je Meta razvila specifično za React Native. Hermes v1, koji dolazi s Expo SDK 55, donosi značajna poboljšanja performansi i podršku za moderne JavaScript značajke.
Ključna poboljšanja Hermes v1
- Brže pokretanje — Hermes kompilira JavaScript u bytecode tijekom izgradnje aplikacije (AOT kompilacija), eliminirajući potrebu za parsiranjem i kompiliranjem u runtime-u
- Poboljšana podrška za moderne JS — Bolja podrška za ES2023+ značajke, uključujući
Array.prototype.toSorted(),Object.groupBy()i dekoratore - Optimizirano upravljanje memorijom — Napredniji garbage collector s manjim pauzama
- Profiliranje performansi — Ugrađeni alati za praćenje koji omogućuju snimanje sesija unutar aplikacije
// Provjera je li Hermes aktivan
const isHermes = () => !!global.HermesInternal;
console.log('Hermes engine:', isHermes() ? 'Aktivan' : 'Neaktivan');
// Korištenje modernih JS značajki s Hermes v1
const brojevi = [3, 1, 4, 1, 5, 9, 2, 6];
const sortirano = brojevi.toSorted(); // Ne mijenja originalni niz
console.log(sortirano); // [1, 1, 2, 3, 4, 5, 6, 9]
const korisnici = [
{ ime: 'Ana', grad: 'Zagreb' },
{ ime: 'Marko', grad: 'Split' },
{ ime: 'Ivana', grad: 'Zagreb' },
];
const poGradu = Object.groupBy(korisnici, k => k.grad);
// { Zagreb: [...], Split: [...] }
Praćenje performansi u novoj arhitekturi
Nova arhitektura donosi i napredne alate za praćenje performansi. Expo SDK 55 uvodi Performance Tracing koji omogućuje detaljnu analizu izvršavanja aplikacije — nešto što nam je definitivno nedostajalo u ranijim verzijama.
Korištenje Performance Tracinga
import { Performance } from 'react-native';
// Mjerenje vremena izvršavanja operacije
performance.mark('pocetak-ucitavanja');
// ... izvršavanje operacije ...
performance.mark('kraj-ucitavanja');
performance.measure(
'ucitavanje-podataka',
'pocetak-ucitavanja',
'kraj-ucitavanja'
);
// Dohvaćanje mjerenja
const mjere = performance.getEntriesByType('measure');
mjere.forEach(m => {
console.log(`${m.name}: ${m.duration}ms`);
});
React DevTools Profiler
React DevTools sada prikazuje detaljne informacije specifične za Fabric renderiranje:
- Commit faze — Koliko vremena Fabric treba za svaki commit ciklus
- Layout izračuni — Vrijeme provedeno u Yoga engine-u za izračun rasporeda
- Nativne operacije — Vizualizacija poziva prema nativnom sloju kroz JSI
Migracija na novu arhitekturu: Praktični vodič
Ako imate postojeći React Native projekt koji još koristi staru arhitekturu, evo detaljnog vodiča za migraciju. Nemojte paničariti — proces je postepan i (uglavnom) bezbolan.
Korak 1: Revizija ovisnosti
Prije svega, provjerite kompatibilnost svih biblioteka koje koristite:
# Generirajte popis ovisnosti
npx react-native info
# Provjerite kompatibilnost na React Native Directory
# https://reactnative.directory/?newArchitecture=true
# Za Expo projekte
npx expo install --check
Više od 850 biblioteka već je kompatibilno s novom arhitekturom, uključujući sve one s više od 200.000 tjednih preuzimanja. No, ako koristite neku nišnu biblioteku, svakako provjerite njezinu kompatibilnost prije nego krenete dalje.
Korak 2: Nadogradnja React Native verzije
# Za Expo projekte
npx expo install expo@latest
npx expo install --fix
# Za bare React Native projekte
npx react-native upgrade
Korak 3: Omogućavanje Hermesa
Hermes je obavezan za novu arhitekturu. Provjerite da je uključen:
// app.json (Expo)
{
"expo": {
"jsEngine": "hermes"
}
}
// android/gradle.properties (bare RN)
hermesEnabled=true
Korak 4: Omogućavanje nove arhitekture
// app.json (Expo)
{
"expo": {
"newArchEnabled": true
}
}
// android/gradle.properties (bare RN)
newArchEnabled=true
// ios/Podfile (bare RN)
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
Korak 5: Migracija prilagođenih nativnih modula
Ako imate vlastite nativne module, trebat ćete ih migrirati na TurboModules. Evo kako taj postupak izgleda:
- Kreirajte TypeScript specifikaciju za svaki modul
- Konfigurirajte Codegen u
package.json - Ažurirajte nativni kod za korištenje TurboModule API-ja
- Testirajte s novom arhitekturom omogućenom
Korak 6: Testiranje i profiliranje
# Pokrenite aplikaciju s novom arhitekturom
npx expo run:ios # ili run:android
# Provjerite logove za eventualna upozorenja
# o nekompatibilnim modulima
# Profilirajte performanse
npx react-native-performance-profiler
Česti problemi pri migraciji i rješenja
Evo najčešćih problema na koje ćete vjerojatno naići (i kako ih riješiti):
- "TurboModule not found" — Provjerite imenovanje specifikacijske datoteke (mora biti
Native*.ts) i konfiguraciju Codegen-a - Crash pri pokretanju — Najčešće je kriva nekompatibilna biblioteka. Provjerite logove, pa ažurirajte ili zamijenite problematičnu biblioteku
- Vizualne nekonzistentnosti — Fabric može drugačije renderirati neke komponente. Testirajte na obje platforme
- TypeScript greške u Codegen-u — Codegen zahtijeva stroge tipske definicije. Koristite
strict: trueutsconfig.json
Expo SDK 55 i nova arhitektura
Expo SDK 55, objavljen u siječnju 2026., predstavlja pravu prekretnicu — to je prva verzija koja isključivo koristi novu arhitekturu i nema povratka na staru. SDK 55 dolazi s React Native 0.83.1 i React 19.2.0.
Nove značajke u SDK 55
- Apple Zoom tranzicije — Podrška za interaktivne tranzicije dijeljenih elemenata na iOS-u koristeći nativne zoom geste
- Stack.Toolbar API — Novi API za UIToolbar na iOS-u koji pruža pristup za izgradnju izbornika i akcija
- SplitView eksperimentalna podrška — Dugo očekivana podrška za podijeljene poglede na tabletima (konačno!)
- expo-brownfield paket — Omogućuje pakiranje React Native koda kao nativne biblioteke (AAR za Android, XCFramework za iOS) koju nativni developeri mogu koristiti bez postavljanja Node.js-a
// Primjer korištenja Apple Zoom tranzicije
import { Stack } from 'expo-router';
export default function Layout() {
return (
<Stack
screenOptions={{
animation: 'zoom', // Nova zoom tranzicija
}}
>
<Stack.Screen name="index" />
<Stack.Screen name="details" />
</Stack>
);
}
// Primjer Stack.Toolbar API-ja
import { Stack } from 'expo-router';
export default function DetailsScreen() {
return (
<>
<Stack.Screen
options={{
title: 'Detalji',
}}
/>
<Stack.Toolbar>
<Stack.Toolbar.Button
title="Uredi"
onPress={() => console.log('Uređivanje')}
/>
<Stack.Toolbar.Button
title="Dijeli"
onPress={() => console.log('Dijeljenje')}
/>
</Stack.Toolbar>
</>
);
}
Usporedba performansi: Stara vs. nova arhitektura
Evo konkretnih brojki iz stvarnih testiranja. Ovi podaci govore sami za sebe:
| Metrika | Stara arhitektura | Nova arhitektura | Poboljšanje |
|---|---|---|---|
| Vrijeme pokretanja (TTI) | ~2.5s | ~1.3s | ~48% |
| Memorijsko korištenje | ~180MB | ~150MB | ~17% |
| FPS tijekom animacija | ~45-55 FPS | ~58-60 FPS | ~15-30% |
| Veličina JS snopa | Referentna | ~10% manja | ~10% |
| Nativni pozivi (latencija) | ~5-10ms | <1ms | ~90% |
Brojke mogu varirati ovisno o složenosti aplikacije, ali trend je neporeciv — nova arhitektura donosi poboljšanja u svim ključnim metrikama.
Najbolje prakse za novu arhitekturu
Na temelju iskustava timova koji su već prošli kroz migraciju, evo što bismo preporučili:
- Započnite s Expo-om — Expo značajno pojednostavljuje korištenje nove arhitekture automatiziranjem konfiguracije i pružanjem kompatibilnih biblioteka
- Koristite stroge TypeScript tipove — Codegen ovisi o preciznim tipskim definicijama. Omogućite
strictmod u TypeScript konfiguraciji - Profilirajte redovito — Koristite Performance Tracing i React DevTools za identificiranje uskih grla
- Migrirajte postupno — Ne pokušavajte sve migrirati odjednom. Interop layer omogućuje postupnu migraciju i to je OK
- Testirajte na stvarnim uređajima — Emulatori ne prikazuju uvijek realno ponašanje, posebno kad je riječ o performansama
- Pratite kompatibilnost biblioteka — Redovito provjeravajte React Native Directory za ažuriranja
Interop Layer: Most između starog i novog
Jedan od najvažnijih aspekata migracije je Interop Layer — sloj kompatibilnosti koji vam omogućuje postupnu migraciju bez potrebe da sve ažurirate odjednom. I moram reći, ovo je možda najmudrija odluka koju je Meta donijela u cijelom procesu.
Kako funkcionira Interop Layer
Interop Layer automatski omotava stare NativeModules i UIManager komponente tako da ih Fabric i TurboModules sustavi mogu koristiti. To u praksi znači da možete omogućiti novu arhitekturu čak i ako neke od vaših biblioteka još koriste stari API.
// Primjer: Stari modul koji radi kroz Interop Layer
// Ovaj kod nastavlja raditi bez izmjena
import { NativeModules } from 'react-native';
const { LegacyAnalytics } = NativeModules;
// Interop Layer automatski preusmjerava pozive
// kroz JSI umjesto kroz stari most
LegacyAnalytics.trackEvent('screen_view', {
screen: 'HomeScreen',
timestamp: Date.now(),
});
// Preporučeni pristup: Migracija na TurboModule
// specs/NativeAnalytics.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
trackEvent(name: string, params: Object): void;
setUserId(id: string): void;
flush(): Promise<boolean>;
}
export default TurboModuleRegistry.getEnforcing<Spec>(
'NativeAnalytics'
);
Ograničenja Interop Layera
Iako je Interop Layer iznimno koristan, treba biti svjestan njegovih ograničenja:
- Performanse — Moduli koji rade kroz Interop Layer ne dobivaju pune prednosti nove arhitekture. Pozivi se i dalje moraju prevoditi između starog i novog API-ja, pa tu ima nešto overhead-a
- Sinkroni pozivi — Stari NativeModules ne podržavaju sinkrone pozive, pa ta mogućnost nije dostupna dok se modul ne migrira na TurboModules
- Deprecation — Interop Layer je privremeno rješenje. Meta planira postupno uklanjati podršku za stari API u budućim verzijama
- Debugiranje — Greške u modulima koji rade kroz Interop Layer mogu biti nešto teže za dijagnostiku jer prolaze kroz dodatni sloj apstrakcije
Debugiranje u novoj arhitekturi
Nova arhitektura donosi poboljšane alate za debugiranje, ali i neke specifičnosti kojih treba biti svjestan.
React Native DevTools
React Native 0.83 uključuje značajna poboljšanja DevTools-a specifična za novu arhitekturu:
- Network Inspector — Praćenje mrežnih zahtjeva izravno u DevTools-u, uključujući WebSocket komunikaciju i GraphQL upite
- Component Inspector — Poboljšani inspektor koji prikazuje Fabric-specifične informacije poput commit faza i layout kalkulacija
- Performance Timeline — Integrirana vremenska crta koja prikazuje JavaScript izvršavanje, React performanse, mrežne događaje i korisnička mjerenja u jednom prikazu
// Korištenje prilagođenih User Timings za debugiranje
performance.mark('fetchStart');
const response = await fetch('https://api.example.com/data');
const data = await response.json();
performance.mark('fetchEnd');
performance.measure('API poziv', 'fetchStart', 'fetchEnd');
// Ove oznake su vidljive u Performance Timeline
// unutar React Native DevTools-a
Flipper i nova arhitektura
Flipper, nekad popularni alat za debugiranje React Native aplikacija, od SDK 55 više nije uključen po zadanim postavkama. React Native DevTools preuzimaju većinu njegovih funkcionalnosti. No, Flipper se i dalje može ručno integrirati za naprednije scenarije:
# Instalacija Flipper podrške (opcionalno)
npx expo install react-native-flipper
# Pokretanje s Flipper podrškom
FLIPPER_ENABLED=1 npx expo run:ios
Česti problemi i rješenja pri debugiranju
Evo praktičnih savjeta za najčešće probleme:
- Module not found greške — Obično su uzrokovane neispravnim imenovanjem specifikacijskih datoteka. Codegen traži datoteke koje prate uzorak
Native*.tsiliNative*.tsx, pa to obavezno provjerite - Tipske greške u Codegen-u — Provjerite da koristite podržane tipove. Codegen ne podržava sve TypeScript tipove — generički tipovi i unija tipovi imaju ograničenu podršku
- Pad performansi pri migraciji — Ako primijetite pad performansi nakon migracije, provjerite rade li neki moduli kroz Interop Layer. Njihova potpuna migracija bi trebala riješiti problem
- Nativne pogreške bez jasnog stack trace-a — Koristite
adb logcatna Androidu i Xcode konzolu na iOS-u za detaljnije nativne logove
Praktični primjer: Izrada kompletnog TurboModula za dijeljenje sadržaja
Za kraj, prođimo kroz izradu kompletnog TurboModula za dijeljenje sadržaja koji koristi nativne API-je obje platforme. Ovaj primjer lijepo demonstrira cijeli tijek rada od specifikacije do gotove komponente.
// specs/NativeShareModule.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
shareText(text: string, title?: string): Promise<boolean>;
shareUrl(url: string, title?: string): Promise<boolean>;
shareImage(
imageUri: string,
message?: string
): Promise<boolean>;
canShare(): boolean;
}
export default TurboModuleRegistry.getEnforcing<Spec>(
'NativeShareModule'
);
A onda implementiramo React komponentu koja koristi taj modul:
// components/ShareButton.tsx
import React, { useCallback } from 'react';
import {
TouchableOpacity,
Text,
Alert,
StyleSheet,
} from 'react-native';
import NativeShareModule from '../specs/NativeShareModule';
interface ShareButtonProps {
content: string;
type: 'text' | 'url' | 'image';
title?: string;
}
export function ShareButton({
content,
type,
title,
}: ShareButtonProps) {
const handleShare = useCallback(async () => {
// Sinkrona provjera mogućnosti dijeljenja
if (!NativeShareModule.canShare()) {
Alert.alert(
'Greška',
'Dijeljenje nije dostupno na ovom uređaju'
);
return;
}
try {
let success = false;
switch (type) {
case 'text':
success = await NativeShareModule.shareText(
content,
title
);
break;
case 'url':
success = await NativeShareModule.shareUrl(
content,
title
);
break;
case 'image':
success = await NativeShareModule.shareImage(
content,
title
);
break;
}
if (success) {
console.log('Sadržaj uspješno podijeljen');
}
} catch (error) {
Alert.alert(
'Greška',
'Nije moguće podijeliti sadržaj'
);
}
}, [content, type, title]);
return (
<TouchableOpacity
style={styles.button}
onPress={handleShare}
>
<Text style={styles.text}>Podijeli</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#007AFF',
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 8,
alignItems: 'center',
},
text: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
});
Ovaj primjer demonstrira ključne prednosti TurboModula: tipsku sigurnost (TypeScript specifikacija jamči ispravne tipove na obje strane), sinkrone pozive (canShare() se izvršava sinkrono), i asinkrone operacije (shareText() vraća Promise). I sve to bez serijalizacije podataka u JSON i slanja preko starog mosta.
Pogled u budućnost
Nova arhitektura React Nativea nije samo tehnička nadogradnja — ona je temelj za budućnost cross-platform mobilnog razvoja. S potpunom eliminacijom mosta, izravnom komunikacijom putem JSI-ja i podrškom za moderne React značajke, React Native se pozicionirao kao ozbiljna alternativa nativnom razvoju čak i za najzahtjevnije aplikacije.
U nadolazećim mjesecima možemo očekivati daljnja poboljšanja Hermes enginea, širu podršku za Concurrent React uzorke, naprednije alate za profiliranje, te još bolju integraciju s nativnim API-jima obje platforme.
S obzirom na to da je 83% Expo projekata već na novoj arhitekturi, smjer je jasan.
Ako još niste migrirali svoj projekt — sada je zapravo idealno vrijeme za početak. Alati su zreli, dokumentacija je opsežna, zajednica je aktivna. Vaši korisnici (i vaše metrike performansi) će vam biti zahvalni.