המדריך המלא לארכיטקטורה החדשה של React Native בשנת 2026
אז שנת 2026 הגיעה, ואיתה נקודת מפנה רצינית בעולם הפיתוח הנייד. React Native, הפריימוורק שבזמנו חולל מהפכה של ממש בפיתוח אפליקציות חוצות-פלטפורמות, עבר שינוי ארכיטקטוני מהותי — כזה שמשנה את כללי המשחק לגמרי. הארכיטקטורה החדשה מבוססת על JSI (JavaScript Interface), מנוע הרינדור Fabric, מערכת TurboModules ומצב Bridgeless. וזה לא סתם שדרוג טכני — זו מהפכה שלמה באופן שבו JavaScript מתקשר עם קוד נייטיב.
בואו נודה באמת — במשך שנים, מפתחי React Native חיו עם מגבלות ה-Bridge הישן. צוואר הבקבוק הזה גרם לעיכובים, ל-jank בממשק המשתמש, ולתחושה מתסכלת של "כמעט נייטיב אבל לא ממש". היום? כל אותן מגבלות פשוט נעלמו. האפליקציות שנבנות עם הארכיטקטורה החדשה מתנהגות כמו אפליקציות נייטיב אמיתיות, עם 60 פריימים בשנייה באופן עקבי ושיפור של עד פי 10 בזמני רינדור. לא מגזים — פי 10.
המדריך הזה מיועד למפתחי React Native ברמה בינונית עד מתקדמת. נצלול לעומק כל רכיב בארכיטקטורה החדשה, נבין איך הוא עובד מתחת למכסה המנוע, נראה דוגמאות קוד מעשיות ונלמד איך לבצע מיגרציה של אפליקציות קיימות. אם אתם רוצים להבין באמת מה השתנה ולמה — הגעתם למקום הנכון.
הבעיה עם ה-Bridge הישן
כדי להעריך את הגדולה של הארכיטקטורה החדשה, חשוב קודם כל להבין מה היה שבור בגרסה הישנה. אני חייב להגיד — כשאתה מבין כמה דברים היו בעייתיים קודם, אתה מעריך את השינוי הרבה יותר.
הארכיטקטורה המקורית של React Native הסתמכה על מנגנון שנקרא Bridge — גשר שחיבר בין עולם ה-JavaScript לעולם הנייטיב (Java/Kotlin ב-Android ו-Objective-C/Swift ב-iOS).
כיצד עבד ה-Bridge הישן
ה-Bridge היה למעשה תור הודעות אסינכרוני. כל תקשורת בין JavaScript לקוד נייטיב עברה דרך תהליך של סריאליזציה (Serialization) ו-דסריאליזציה (Deserialization) בפורמט JSON. כלומר — כאשר JavaScript רצה לעדכן את ממשק המשתמש או לקרוא לפונקציה נייטיבית, ההודעה הומרה ל-JSON, נשלחה דרך ה-Bridge, פוענחה בצד השני, בוצעה, והתוצאה חזרה באותו תהליך הסרבולי.
נסו לדמיין את זה ככה: שני אנשים יושבים בחדרים נפרדים ומתקשרים רק דרך מכתבים. כל מכתב צריך להיכתב, להישלח, להתקבל ולהיקרא — במקום פשוט לדבר ישירות פנים אל פנים. זה בדיוק מה שקרה עם ה-Bridge. מטורף, לא?
הבעיות המרכזיות
- תקשורת אסינכרונית בלבד — כל קריאה מ-JavaScript לנייטיב הייתה אסינכרונית. לא ניתן היה לקבל ערך חזרה באופן סינכרוני, מה שהקשה מאוד על מימוש תבניות עיצוב מסוימות.
- צוואר בקבוק בסריאליזציה — המרת אובייקטים ל-JSON ובחזרה דרשה זמן עיבוד משמעותי, במיוחד עם מבני נתונים גדולים או תדירות תקשורת גבוהה.
- עומס על ה-Bridge — כשהרבה הודעות נשלחו בו-זמנית (למשל בזמן גלילה מהירה ואנימציות), ה-Bridge פשוט נחנק. התוצאה? קפיצות ועיכובים בממשק.
- חוסר יכולת לשתף זיכרון — JavaScript ונייטיב לא יכלו לגשת לאותו מרחב זיכרון, מה שהכריח העתקת נתונים בין הצדדים (וזה כואב בביצועים).
- אתחול איטי — כל המודולים הנייטיביים נטענו בעת הפעלת האפליקציה, גם אם לא היה בהם צורך מיידי. המשתמש יושב ומחכה, ואתה טוען מודולים שאולי אף אחד לא ישתמש בהם.
הבעיות האלה הפכו בולטות במיוחד באפליקציות מורכבות — אלה עם רשימות ארוכות, אנימציות מתוחכמות ואינטראקציות מהירות. מניסיוני, הפער בביצועים בין אפליקציית React Native לאפליקציה נייטיבית טהורה היה מורגש מאוד, ולפעמים ממש מתסכל. מכירים את הרגע שהלקוח אומר "למה זה לא חלק כמו באפליקציה של המתחרים"? כן, זה בדיוק מה שקרה.
JSI — JavaScript Interface: התקשורת הישירה
JSI (JavaScript Interface) הוא לב ליבה של הארכיטקטורה החדשה. בגדול, זו שכבת תקשורת דקה כתובה ב-C++ שמאפשרת ל-JavaScript לגשת ישירות לאובייקטים ופונקציות נייטיביים — ללא סריאליזציה, ללא JSON, ללא Bridge. פשוט ישירות.
איך JSI עובד
במקום לשלוח הודעות JSON דרך תור אסינכרוני, JSI חושף אובייקטים נייטיביים ישירות למנוע ה-JavaScript. כשקוד JavaScript קורא לפונקציה נייטיבית דרך JSI, זוהי קריאת פונקציה רגילה — בדיוק כמו קריאה לפונקציית JavaScript רגילה אחרת. אין תהליך המרה, אין עלות תקשורת נוספת. פשוט עובד.
העקרונות המרכזיים:
- תקשורת סינכרונית — JavaScript יכול לקרוא לפונקציה נייטיבית ולקבל תוצאה מיידית. בלי Promise, בלי callback. פשוט קוראים ומקבלים.
- שיתוף זיכרון — JavaScript ונייטיב יכולים לגשת לאותו מרחב זיכרון, מה שמבטל לחלוטין את הצורך בהעתקת נתונים. זה לבד שווה הרבה.
- אגנוסטי למנוע JavaScript — JSI מגדיר ממשק אחיד שלא תלוי במנוע ספציפי, כך שאפשר להחליף בין Hermes, V8 או JavaScriptCore ללא שינויי קוד.
- ביצועים כמו נייטיב — מכיוון שאין תקורת תקשורת, הביצועים מתקרבים לאלו של קוד נייטיב טהור. ואני לא מגזים.
דוגמת קוד: Host Object דרך JSI
הנה דוגמה מפושטת שממחישה איך אובייקט נייטיב נחשף ל-JavaScript דרך JSI:
// C++ side - Exposing a native object via JSI
#include <jsi/jsi.h>
using namespace facebook::jsi;
class DeviceInfoModule : public HostObject {
public:
Value get(Runtime& runtime, const PropNameID& name) override {
std::string propName = name.utf8(runtime);
if (propName == "getBatteryLevel") {
return Function::createFromHostFunction(
runtime,
PropNameID::forAscii(runtime, "getBatteryLevel"),
0, // number of arguments
[](Runtime& runtime, const Value& thisVal,
const Value* args, size_t count) -> Value {
// Direct native call - no serialization!
double batteryLevel = NativeBattery::getLevel();
return Value(batteryLevel);
}
);
}
if (propName == "getDeviceModel") {
return String::createFromUtf8(
runtime, NativeDevice::getModel()
);
}
return Value::undefined();
}
};
// Register the host object
runtime.global().setProperty(
runtime,
"DeviceInfo",
Object::createFromHostObject(
runtime,
std::make_shared<DeviceInfoModule>()
)
);
ובצד JavaScript? השימוש פשוט להפליא:
// JavaScript side - Using the JSI object directly
// No bridge, no async, no JSON serialization
// Synchronous call - returns value immediately!
const batteryLevel = global.DeviceInfo.getBatteryLevel();
console.log(`Battery: ${batteryLevel}%`);
// Direct property access
const model = global.DeviceInfo.getDeviceModel;
console.log(`Device: ${model}`);
שימו לב לפשטות — אין await, אין NativeModules, אין סריאליזציה. הקריאה ישירה וסינכרונית. וזה בדיוק השינוי הפרדיגמטי שמניע את כל שאר השיפורים בארכיטקטורה החדשה.
Fabric — מנוע הרינדור החדש
Fabric הוא מנוע הרינדור החדש של React Native, שמחליף את ה-UIManager הישן. הוא נבנה מאפס עם JSI כבסיס, ומביא שיפורים דרמטיים בביצועי הרינדור ובחוויית המשתמש. אני חייב להגיד — כשראיתי את ההבדל בפעם הראשונה, זה היה רגע "וואו" אמיתי.
ליבת C++ משותפת
אחד החידושים המרכזיים של Fabric הוא שליבת הרינדור כתובה ב-C++ ומשותפת לשתי הפלטפורמות (iOS ו-Android). מה זה אומר בפועל? שהלוגיקה של חישוב ה-Layout, בניית עץ הצל (Shadow Tree) והשוואת ההבדלים מתבצעת פעם אחת בקוד אחיד, במקום פעמיים בשפות שונות. פחות קוד, פחות באגים, יותר עקביות.
עץ הצל הבלתי-ניתן-לשינוי (Immutable Shadow Tree)
Fabric משתמש ב-Shadow Tree בלתי-ניתן-לשינוי (immutable). כל שינוי בממשק המשתמש יוצר עץ צל חדש במקום לשנות את הקיים. למה זה טוב? כמה סיבות:
- Thread Safety — מכיוון שהעץ לא משתנה אחרי שנוצר, מספר threads יכולים לקרוא אותו בו-זמנית בלי חשש מ-race conditions. מי שהתמודד עם באגי race conditions יודע כמה זה שווה.
- רינדור מבוסס עדיפויות — המערכת יכולה להחליט אילו עדכונים חשובים יותר ולטפל בהם קודם, מה שמשפר את הרספונסיביות.
- ביטול עדכונים — אם עדכון חדש מגיע לפני שהקודם הסתיים, אפשר פשוט לזרוק את העץ הישן ולעבוד עם החדש. אלגנטי.
רינדור מקבילי עם React 18/19
Fabric תומך באופן מלא ב-Concurrent Rendering של React 18 ו-React 19. בפועל, זה אומר שתכונות כמו Suspense, useTransition ו-startTransition עובדות באופן מלא גם ב-React Native. המשתמש מרגיש ממשק חלק ומגיב גם כשמתבצעים עדכונים כבדים ברקע — וזה משהו שפעם היה חלום רחוק.
import React, { useState, useTransition, Suspense } from 'react';
import { View, Text, Pressable, ActivityIndicator } from 'react-native';
// Concurrent rendering in action with Fabric
function ProductCatalog() {
const [category, setCategory] = useState('all');
const [isPending, startTransition] = useTransition();
const handleCategoryChange = (newCategory: string) => {
// High priority - update the UI immediately
setSelectedTab(newCategory);
// Low priority - can be interrupted
startTransition(() => {
setCategory(newCategory);
});
};
return (
<View>
<CategoryTabs
onSelect={handleCategoryChange}
isPending={isPending}
/>
<Suspense fallback={<ActivityIndicator size="large" />}>
<ProductList category={category} />
</Suspense>
</View>
);
}
// React 19 - use() hook for data fetching
function ProductList({ category }: { category: string }) {
const products = use(fetchProducts(category));
return (
<FlatList
data={products}
renderItem={({ item }) => <ProductCard product={item} />}
keyExtractor={(item) => item.id}
/>
);
}
ההבדלים העיקריים מ-UIManager הישן
ב-UIManager הישן, כל פעולות הרינדור עברו דרך ה-Bridge האסינכרוני. פקודות כמו createView, updateView ו-manageChildren נשלחו כהודעות JSON ובוצעו ב-batch בצד הנייטיב. זה יצר עיכוב מובנה — פער זמן בין הרגע שבו React החליט על שינוי לבין הרגע שבו המשתמש ראה אותו על המסך.
ב-Fabric, הכל מתבצע סינכרונית דרך JSI. React Native יכול לבנות את עץ הצל, לחשב Layout ולעדכן את ממשק המשתמש הנייטיבי — הכל ב-frame אחד. התוצאה? ממשק חלק יותר, רספונסיבי יותר, עם פחות jank. המשתמשים מרגישים את זה גם אם הם לא יודעים לנסח למה.
TurboModules — מודולים חכמים יותר
TurboModules מחליפים את מערכת NativeModules הישנה עם גישה מודרנית, יעילה ובטוחה מבחינת טיפוסים. הם מנצלים את JSI כדי לספק ביצועים מעולים וחוויית פיתוח משופרת משמעותית.
טעינה עצלנית (Lazy Loading)
אחד השינויים הכי משמעותיים? טעינה עצלנית. בעוד שב-NativeModules הישן כל המודולים נטענו בעת הפעלת האפליקציה (גם אם אף אחד לא ישתמש בהם), TurboModules נטענים רק כשמישהו קורא להם בפעם הראשונה. זה מקצר בצורה דרמטית את זמן ההפעלה, במיוחד באפליקציות גדולות עם עשרות מודולים נייטיביים. וידעו — באפליקציות פרודקשן גדולות, ההבדל מורגש מהשנייה הראשונה.
בטיחות טיפוסים עם Codegen
TurboModules משתמשים ב-Codegen — כלי שמייצר אוטומטית קוד boilerplate נייטיבי מהגדרות TypeScript/Flow. אתם מגדירים את הממשק ב-JavaScript, ו-Codegen עושה את כל העבודה המלוכלכה ויוצר את הקוד הנייטיבי הנדרש. זה מבטיח שהטיפוסים תואמים בשני הצדדים ומונע שגיאות runtime מביכות.
מתודות סינכרוניות
בזכות JSI, TurboModules תומכים ב-מתודות סינכרוניות שמחזירות ערכים מיידית. יכולת שלא הייתה אפשרית כלל עם ה-Bridge הישן. לדעתי, זה אחד הדברים שהכי משנים את חוויית הפיתוח היומיומית.
דוגמה מעשית: הגדרת TurboModule Spec
// NativeDeviceInfo.ts - TurboModule Specification
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
// Synchronous method - returns value immediately
getDeviceModel(): string;
// Synchronous method with return value
getBatteryLevel(): number;
// Async method for long operations
getStorageInfo(): Promise<{
total: number;
used: number;
free: number;
}>;
// Method with parameters
setPreference(key: string, value: string): boolean;
// Method with complex types
getSystemInfo(): {
os: string;
version: string;
buildNumber: string;
isEmulator: boolean;
};
// Constants that are computed once at init
getConstants(): {
appVersion: string;
buildVersion: string;
bundleId: string;
};
}
// Register with TurboModuleRegistry
export default TurboModuleRegistry.getEnforcing<Spec>(
'DeviceInfo'
);
ושימוש ב-TurboModule בקומפוננטה:
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import NativeDeviceInfo from './NativeDeviceInfo';
function DeviceInfoScreen() {
const [storageInfo, setStorageInfo] = useState(null);
// Synchronous - no await needed!
const deviceModel = NativeDeviceInfo.getDeviceModel();
const batteryLevel = NativeDeviceInfo.getBatteryLevel();
const constants = NativeDeviceInfo.getConstants();
useEffect(() => {
// Async only for truly long operations
async function loadStorage() {
const info = await NativeDeviceInfo.getStorageInfo();
setStorageInfo(info);
}
loadStorage();
}, []);
return (
<View style={{ padding: 20 }}>
<Text>Device: {deviceModel}</Text>
<Text>Battery: {batteryLevel}%</Text>
<Text>App Version: {constants.appVersion}</Text>
{storageInfo && (
<Text>
Storage: {storageInfo.used}GB / {storageInfo.total}GB
</Text>
)}
</View>
);
}
רואים? getDeviceModel() ו-getBatteryLevel() נקראים סינכרונית ישירות בתוך גוף הקומפוננטה, בלי await ובלי useEffect. זה אפשרי רק בזכות JSI ו-TurboModules, וזה משנה לגמרי את הדרך שבה אנחנו כותבים קוד.
מצב Bridgeless — הצעד האחרון
מצב Bridgeless (ללא גשר) הוא השלב הסופי — וגם המשמעותי ביותר — בארכיטקטורה החדשה. זה לא סתם עוד שדרוג. זו הסרה מוחלטת של ה-Bridge מהמערכת. גמרנו איתו. החל מ-React Native 0.73, מצב Bridgeless הפך לברירת המחדל.
מה זה אומר בפועל?
במצב Bridgeless, כל הרכיבים שהסתמכו בעבר על ה-Bridge הועברו למנגנונים חדשים:
- טיפול בשגיאות (Error Handling) — הועבר ממנגנון ה-Bridge למנגנון ישיר דרך JSI.
- Event Emitters — אירועים נשלחים ישירות דרך JSI במקום דרך תור ההודעות של ה-Bridge.
- טיימרים (Timers) —
setTimeout,setIntervalו-requestAnimationFrameכולם עובדים דרך JSI. - מודולים נייטיביים — כל המודולים עברו ל-TurboModules.
- רינדור ממשק משתמש — כולו דרך Fabric.
בקיצור, לא נשאר שום דבר שעובר דרך ה-Bridge הישן. הוא פשוט לא שם יותר.
הפעלה והגדרה
באפליקציות חדשות שנוצרות עם React Native 0.73 ומעלה, מצב Bridgeless מופעל כברירת מחדל. לאפליקציות קיימות, ההפעלה נראית כך:
// react-native.config.js
module.exports = {
// Bridgeless mode is default since RN 0.73+
// For older versions, enable explicitly:
project: {
ios: {
unstable_newArchEnabled: true,
},
android: {
unstable_newArchEnabled: true,
},
},
};
// Android - gradle.properties
newArchEnabled=true
// iOS - Podfile
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
כשמצב Bridgeless פעיל, האפליקציה כבר לא מכילה שום קוד של ה-Bridge הישן. זה מפחית את גודל ה-bundle, משפר את זמן ההפעלה ומבטיח שכל התקשורת עוברת דרך הנתיבים החדשים והמהירים. ניקיון אמיתי.
Expo SDK 53 והארכיטקטורה החדשה
Expo, הכלי הפופולרי ביותר לפיתוח React Native, אימץ את הארכיטקטורה החדשה באופן מלא ב-SDK 53. אם אתם משתמשים ב-Expo (ובשנת 2026, מי לא?) — זה רגע משמעותי עבורכם.
מה חדש ב-Expo SDK 53
- ארכיטקטורה חדשה כברירת מחדל — כל פרויקט חדש שנוצר עם Expo SDK 53 משתמש בארכיטקטורה החדשה מיד, בלי שום הגדרה ידנית. פשוט עובד מהקופסה.
- React Native 0.79 — הגרסה היציבה האחרונה עם כל התיקונים והשיפורים.
- React 19 — תמיכה מלאה ב-React 19, כולל Server Components, ה-hook החדש
use()ושיפורים ב-Suspense. - expo-audio (יציב) — API חדש ומודרני לניהול אודיו, שמחליף את
expo-avהישן (סוף סוף!). - expo-maps (אלפא) — API חדש למפות, שמביא חוויה מודרנית ומותאמת לארכיטקטורה החדשה.
- expo-background-task — API חדש להרצת משימות ברקע. חיוני לאפליקציות שצריכות לבצע עבודה כשהן לא בפוקוס.
צעדים מעשיים ליצירת פרויקט עם Expo SDK 53
# Create a new Expo project with SDK 53
npx create-expo-app@latest my-app
cd my-app
# The new architecture is enabled by default!
# Verify in app.json:
cat app.json
// app.json - Expo SDK 53
{
"expo": {
"name": "my-app",
"slug": "my-app",
"version": "1.0.0",
"sdkVersion": "53.0.0",
"newArchEnabled": true, // Default: true in SDK 53
"ios": {
"bundleIdentifier": "com.example.myapp"
},
"android": {
"package": "com.example.myapp"
},
"plugins": [
"expo-router",
"expo-audio",
"expo-background-task"
]
}
}
ושימוש ב-API החדש של expo-audio:
import { useAudioPlayer, AudioModule } from 'expo-audio';
import { useEffect } from 'react';
import { View, Pressable, Text } from 'react-native';
export default function MusicPlayer() {
const player = useAudioPlayer(
require('./assets/music.mp3')
);
useEffect(() => {
// Request audio permissions
AudioModule.requestRecordingPermissionsAsync();
// Set audio mode
AudioModule.setAudioModeAsync({
playsInSilentMode: true,
shouldRouteThroughEarpiece: false,
});
}, []);
return (
<View style={{ padding: 20 }}>
<Pressable onPress={() => player.play()}>
<Text>Play</Text>
</Pressable>
<Pressable onPress={() => player.pause()}>
<Text>Pause</Text>
</Pressable>
<Text>
Duration: {Math.round(player.duration)}s
</Text>
<Text>
Position: {Math.round(player.currentTime)}s
</Text>
</View>
);
}
מדריך מיגרציה — צעד אחר צעד
אז מיגרציה לארכיטקטורה החדשה יכולה להישמע מפחידה. אני מבין. אבל עם גישה מסודרת, התהליך ממש ניתן לניהול. עשיתי את זה בכמה פרויקטים, ואחרי הפעם הראשונה זה נהיה הרבה יותר קל. הנה מדריך מעשי.
שלב 1: עדכון תלויות
קודם כל, ודאו שכל הספריות שלכם תומכות בארכיטקטורה החדשה. בשנת 2026 רוב הספריות הפופולריות כבר תומכות, אבל תמיד כדאי לבדוק — יש כאלה שמפתיעות לרעה.
# Check compatibility of your dependencies
npx react-native-new-arch-check
# Update React Native to latest version
npx react-native upgrade
# For Expo projects - update SDK
npx expo install expo@latest
# Update all Expo packages to compatible versions
npx expo install --fix
שלב 2: הפעלת הארכיטקטורה החדשה
// For bare React Native projects:
// android/gradle.properties
newArchEnabled=true
// ios/Podfile - add at the top
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
// Then reinstall pods
cd ios && pod install && cd ..
// For Expo projects:
// app.json
{
"expo": {
"newArchEnabled": true
}
}
שלב 3: מיגרציה של NativeModules ל-TurboModules
אם יש לכם מודולים נייטיביים מותאמים אישית, הם צריכים לעבור ל-TurboModules. הנה לפני ואחרי — שימו לב לפער:
// BEFORE - Old NativeModules pattern
// MyModule.js
import { NativeModules } from 'react-native';
const { MyNativeModule } = NativeModules;
// Always async, no type safety
MyNativeModule.doSomething('param', (result) => {
console.log(result);
});
// ============================================
// AFTER - TurboModules pattern
// NativeMyModule.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
doSomething(param: string): Promise<string>;
doSomethingSync(param: string): string; // Sync!
}
export default TurboModuleRegistry.getEnforcing<Spec>(
'MyModule'
);
// Usage - type-safe and can be synchronous
import NativeMyModule from './NativeMyModule';
const result = NativeMyModule.doSomethingSync('param');
שלב 4: מיגרציה של קומפוננטות נייטיביות ל-Fabric
// BEFORE - Old requireNativeComponent
import { requireNativeComponent } from 'react-native';
const MyNativeView = requireNativeComponent('MyNativeView');
// ============================================
// AFTER - Fabric component with codegenNativeComponent
import codegenNativeComponent from
'react-native/Libraries/Utilities/codegenNativeComponent';
import type { ViewProps } from 'react-native';
interface NativeProps extends ViewProps {
color: string;
size: number;
onCustomEvent?: (event: {
nativeEvent: { value: string }
}) => void;
}
export default codegenNativeComponent<NativeProps>(
'MyNativeView'
);
שלב 5: בדיקות ותיקונים
# Run the app and test thoroughly
npx react-native run-android
npx react-native run-ios
# For Expo
npx expo run:android
npx expo run:ios
# Run your test suite
npm test
# Check for console warnings about deprecated APIs
# Fix any bridge-related warnings
טיפ חשוב (ומניסיון אישי): בצעו את המיגרציה בשלבים. אל תנסו להעביר הכל בבת אחת — זו מתכון לכאב ראש. התחילו עם הפעלת הארכיטקטורה החדשה, ואז טפלו בבעיות שצצות אחת אחת. נשמע יותר איטי, אבל בפועל זה חוסך המון זמן דיבוג.
השוואת ביצועים — לפני ואחרי
מספרים לא משקרים, אז בואו ניכנס לנתונים.
רינדור רשימות
FlashList v2, שנבנה מחדש במיוחד עבור הארכיטקטורה החדשה, מדגים את השיפורים בצורה הכי טובה:
- ארכיטקטורה ישנה: רשימה של 10,000 פריטים עם קומפוננטות מורכבות — ירידה ל-30-40 FPS בזמן גלילה מהירה, JS thread ב-70-90% ניצולת. לא נעים.
- ארכיטקטורה חדשה: אותה רשימה בדיוק — 60 FPS עקביים, JS thread מתחת ל-10% ניצולת. פשוט עולם אחר.
מדדי ביצועים מרכזיים
- זמן רינדור — שיפור של עד פי 10 בזמני רינדור של קומפוננטות מורכבות.
- זמן הפעלה (Startup Time) — שיפור של 30-50% בזכות טעינה עצלנית של TurboModules.
- צריכת זיכרון — ירידה של 20-30% בזכות שיתוף זיכרון דרך JSI וביטול העתקות JSON.
- תגובתיות (Responsiveness) — זמן תגובה לאינטראקציות משתמש ירד מ-100-200ms ל-16-32ms. ההבדל בין "מרגיש אטי" ל"מרגיש מיידי".
- אנימציות — אנימציות מורכבות רצות ב-60 FPS באופן עקבי, ללא frame drops.
// Performance monitoring example
import { PerformanceObserver } from 'react-native';
// Measure component render times
function PerformanceMonitor() {
useEffect(() => {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.duration}ms`);
// With new architecture, expect:
// Component renders: < 2ms (was 10-20ms)
// List item recycle: < 1ms (was 5-10ms)
// Native module call: < 0.1ms (was 1-5ms)
}
});
observer.observe({ entryTypes: ['measure'] });
return () => observer.disconnect();
}, []);
return null;
}
דוגמה עם FlashList v2
import { FlashList } from '@shopify/flash-list';
import React, { useCallback } from 'react';
import { View, Text, Image } from 'react-native';
// FlashList v2 - rebuilt for new architecture
function OptimizedProductList({ products }) {
const renderItem = useCallback(({ item }) => (
<View style={{ flexDirection: 'row', padding: 12 }}>
<Image
source={{ uri: item.imageUrl }}
style={{ width: 80, height: 80, borderRadius: 8 }}
/>
<View style={{ flex: 1, marginLeft: 12 }}>
<Text style={{ fontSize: 16, fontWeight: 'bold' }}>
{item.name}
</Text>
<Text style={{ color: '#666', marginTop: 4 }}>
{item.description}
</Text>
<Text style={{ fontSize: 18, color: '#007AFF' }}>
${item.price}
</Text>
</View>
</View>
), []);
return (
<FlashList
data={products}
renderItem={renderItem}
estimatedItemSize={104}
keyExtractor={(item) => item.id}
// With new architecture:
// - Consistent 60 FPS scrolling
// - JS thread stays below 10%
// - No blank cells during fast scroll
/>
);
}
Reanimated 4 והארכיטקטורה החדשה
React Native Reanimated 4 הוא שדרוג רציני של ספריית האנימציות הפופולרית ביותר ב-React Native. הגרסה החדשה מנצלת את הארכיטקטורה החדשה באופן מלא ומביאה שני חידושים מרכזיים שאני חייב להגיד — שינו לי את הדרך שבה אני חושב על אנימציות: API של אנימציות CSS ו-Worklets כמנוע מקבילי לשימוש כללי.
API חדש לאנימציות CSS
Reanimated 4 מציג גישה דקלרטיבית חדשה לאנימציות, מבוססת על תחביר CSS Animations מוכר. במקום לכתוב קוד אימפרטיבי עם useSharedValue ו-useAnimatedStyle, אתם יכולים פשוט להגדיר אנימציות בסגנון CSS. אם עבדתם פעם עם CSS Animations בווב — תרגישו ממש בבית.
import React from 'react';
import { View, Text, Pressable } from 'react-native';
import Animated, {
createCSSAnimation,
createCSSTransition,
} from 'react-native-reanimated';
// CSS Keyframe Animation - declarative approach
const bounceIn = createCSSAnimation({
keyframes: {
'0%': {
transform: [{ scale: 0.3 }],
opacity: 0,
},
'50%': {
transform: [{ scale: 1.05 }],
opacity: 0.8,
},
'70%': {
transform: [{ scale: 0.9 }],
opacity: 1,
},
'100%': {
transform: [{ scale: 1 }],
opacity: 1,
},
},
duration: '600ms',
timingFunction: 'ease-out',
fillMode: 'both',
});
// CSS Transition - smooth state changes
const smoothTransition = createCSSTransition({
property: ['transform', 'backgroundColor', 'opacity'],
duration: '300ms',
timingFunction: 'ease-in-out',
});
function AnimatedCard({ isExpanded, onPress }) {
return (
<Pressable onPress={onPress}>
<Animated.View
style={[
{
padding: 20,
borderRadius: 12,
backgroundColor: isExpanded ? '#007AFF' : '#F0F0F0',
transform: [{ scale: isExpanded ? 1.05 : 1 }],
opacity: isExpanded ? 1 : 0.8,
},
smoothTransition, // Apply CSS transition
]}
>
<Text style={{
color: isExpanded ? '#FFF' : '#333'
}}>
Tap to {isExpanded ? 'collapse' : 'expand'}
</Text>
</Animated.View>
</Pressable>
);
}
// Entry animation using keyframes
function WelcomeScreen() {
return (
<Animated.View style={[{ flex: 1 }, bounceIn]}>
<Text style={{ fontSize: 32 }}>Welcome!</Text>
</Animated.View>
);
}
Worklets כמנוע מקבילי לשימוש כללי
אחד השינויים הכי מעניינים ב-Reanimated 4 הוא ההפרדה של Worklets לספרייה עצמאית בשם react-native-worklets. Worklets הם כבר לא רק כלי לאנימציות — הם הפכו למנוע מקביליות לשימוש כללי (General-Purpose Concurrency Engine). וזה, לדעתי, אחד הדברים הכי מרגשים שקרו ל-React Native בשנים האחרונות.
המשמעות? אתם יכולים להריץ כל חישוב כבד ב-thread נפרד, מבלי לחסום את ה-JS thread או את ה-UI thread:
import { useWorklet, runOnWorker } from
'react-native-worklets';
// Heavy computation running on a separate thread
function ImageProcessor() {
const processImage = useWorklet('default', (
pixels: number[],
filter: string
) => {
'worklet';
// This runs on a separate thread!
// JS thread and UI thread remain free
const result = new Array(pixels.length);
for (let i = 0; i < pixels.length; i += 4) {
if (filter === 'grayscale') {
const avg = (
pixels[i] + pixels[i + 1] + pixels[i + 2]
) / 3;
result[i] = avg; // R
result[i + 1] = avg; // G
result[i + 2] = avg; // B
result[i + 3] = pixels[i + 3]; // A
}
}
return result;
});
const handleProcess = async () => {
const imageData = await loadImagePixels();
// Runs on worker thread - UI stays responsive
const processed = await runOnWorker(
processImage,
imageData,
'grayscale'
);
displayResult(processed);
};
return (
<Pressable onPress={handleProcess}>
<Text>Process Image</Text>
</Pressable>
);
}
היכולת להריץ קוד JavaScript ב-thread נפרד בלי לחסום את ה-UI זה game-changer אמיתי. חשבו על זה — עד עכשיו, כל חישוב כבד ב-JavaScript חסם את ה-thread הראשי וגרם לקפיאת הממשק. עם Worklets, אתם יכולים להריץ עיבוד תמונה, ניתוח נתונים ואלגוריתמים כבדים ברקע, בזמן שהממשק נשאר חלק ומגיב לחלוטין. זה סוג הדברים שפעם היינו צריכים לכתוב קוד נייטיב בשבילם.
שיטות עבודה מומלצות (Best Practices)
אחרי שעברנו על כל הרכיבים, הנה אוסף של טיפים ושיטות עבודה שלמדתי מהשטח. חלקם נראים מובנים מאליהם, אבל תאמינו לי — קל לשכוח אותם ברגע שמתחילים לפתח.
1. נצלו מתודות סינכרוניות בחוכמה
אחד היתרונות הגדולים של TurboModules הוא היכולת לקרוא למתודות נייטיביות באופן סינכרוני. אבל — וזה "אבל" חשוב — צריך להשתמש ביכולת הזו בחוכמה. רק עבור פעולות קצרות וקלות. פעולות כבדות (כמו קריאות רשת או גישה לקבצים גדולים) צריכות להישאר אסינכרוניות. אחרת אתם פשוט חוסמים את ה-thread בדרך אחרת.
// Good - short, fast operations as synchronous
const locale = NativeLocale.getCurrentLocale();
const isDarkMode = NativeAppearance.getColorScheme();
// Bad - heavy operations should remain async
// Don't do this synchronously!
// const data = NativeDatabase.queryAllRecords();
// Instead, use async for heavy operations
const data = await NativeDatabase.queryAllRecords();
2. השתמשו ב-Codegen לבטיחות טיפוסים
תמיד הגדירו את ה-Spec של ה-TurboModules שלכם ב-TypeScript. ה-Codegen ייצר אוטומטית את הקוד הנייטיבי עם בטיחות טיפוסים מלאה. אל תדלגו על השלב הזה. רציני. ראיתי מפתחים שחשבו שזה מיותר ושילמו על זה ביום-יומיים של דיבוג.
3. מנפו את Concurrent Rendering
השתמשו ב-useTransition ו-Suspense כדי להבטיח שהממשק נשאר מגיב גם בזמן עדכונים כבדים. זה אחד הדברים שהכי משפרים את חוויית המשתמש:
import { useTransition } from 'react';
function SearchScreen() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
const handleSearch = (text: string) => {
// Immediate update - user sees typing right away
setQuery(text);
// Deferred update - won't block typing
startTransition(() => {
const filtered = performExpensiveSearch(text);
setResults(filtered);
});
};
return (
<View>
<TextInput value={query} onChangeText={handleSearch} />
{isPending && <ActivityIndicator />}
<ResultsList data={results} />
</View>
);
}
4. העדיפו FlashList על FlatList
ברשימות ארוכות, FlashList v2 מציע ביצועים מעולים עם הארכיטקטורה החדשה. הוא נבנה מחדש במיוחד עבור Fabric ומנצל את שיתוף הזיכרון של JSI. פשוט תחליפו FlatList ב-FlashList ותראו הבדל מיידי.
5. השתמשו ב-CSS Animations של Reanimated 4
לאנימציות פשוטות ובינוניות, ה-API החדש של CSS Animations פשוט ויעיל יותר מה-API האימפרטיבי. שמרו את useSharedValue ו-useAnimatedStyle למקרים מורכבים שבאמת דורשים שליטה מלאה. אין צורך לסבך דברים כשיש דרך פשוטה יותר.
6. הפרידו חישובים כבדים ל-Worklets
כלל אצבע: כל חישוב שלוקח יותר ממספר מילישניות צריך לרוץ ב-Worklet ב-thread נפרד. זה כולל עיבוד מחרוזות כבד, חישובים מתמטיים מורכבים, מיון וסינון של מערכים גדולים ועיבוד נתונים. ה-UI thread שלכם יודה לכם.
7. מנטרו ביצועים באופן שוטף
import { useEffect } from 'react';
// Custom hook for monitoring render performance
function useRenderPerformance(componentName: string) {
useEffect(() => {
const startTime = performance.now();
return () => {
const endTime = performance.now();
const duration = endTime - startTime;
if (duration > 16) {
// Longer than one frame (16ms)
console.warn(
`[Perf] ${componentName} render: ${duration.toFixed(2)}ms`
);
}
};
});
}
// Usage
function ExpensiveComponent() {
useRenderPerformance('ExpensiveComponent');
// ... component logic
}
8. עדכנו ספריות צד שלישי
ודאו שכל הספריות שלכם מעודכנות ותומכות בארכיטקטורה החדשה. בשנת 2026 רוב הספריות הפופולריות כבר מעודכנות, אבל ייתכנו ספריות ישנות שעדיין לא ביצעו מיגרציה. בדקו את עמוד התאימות הרשמי של React Native — זה יחסוך לכם הפתעות לא נעימות.
9. טפלו נכון בשגיאות במצב Bridgeless
import { ErrorUtils } from 'react-native';
// Global error handler for bridgeless mode
ErrorUtils.setGlobalHandler((error, isFatal) => {
if (isFatal) {
// Report fatal error to crash reporting service
CrashReporter.recordFatal(error);
} else {
// Log non-fatal errors
CrashReporter.recordError(error);
}
});
// Component-level error boundary
class AppErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
CrashReporter.recordError(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <ErrorFallbackScreen />;
}
return this.props.children;
}
}
10. תכננו את מבנה הפרויקט בהתאם
ארגנו את קבצי ה-Spec של TurboModules ו-Fabric Components בתיקיות ייעודיות. זה נשמע טריוויאלי, אבל מבנה תיקיות נכון חוסך כאב ראש בהמשך. הנה מבנה שעובד טוב:
src/
├── components/
│ ├── native/ # Fabric native components
│ │ ├── MyNativeView.tsx
│ │ └── MyNativeInput.tsx
│ └── js/ # Regular React components
├── modules/
│ ├── specs/ # TurboModule specifications
│ │ ├── NativeDeviceInfo.ts
│ │ └── NativeStorage.ts
│ └── implementations/ # JS-side module logic
├── worklets/ # Worklet functions
│ ├── imageProcessing.ts
│ └── dataTransforms.ts
├── animations/ # Reanimated CSS animations
│ ├── transitions.ts
│ └── keyframes.ts
└── screens/
סיכום ומבט לעתיד
אז בואו נסכם. הארכיטקטורה החדשה של React Native היא לא סתם עדכון טכני — היא מהפכה שמשנה לגמרי את הנרטיב של פיתוח אפליקציות חוצות-פלטפורמות. עם JSI שמאפשר תקשורת ישירה וסינכרונית, Fabric שמביא רינדור מקבילי ברמת נייטיב, TurboModules שמספקים טעינה חכמה ובטיחות טיפוסים, ומצב Bridgeless שמסיר כל שאריות של העבר — אפליקציות React Native בשנת 2026 הן פשוט משהו אחר.
הפער בביצועים בין אפליקציית React Native לאפליקציה נייטיבית טהורה? כמעט ונעלם.
עם שיפור של עד פי 10 ברינדור, 60 FPS עקביים ברשימות מורכבות וזמני תגובה של מילישניות בודדות — אני חייב לשאול: מה עוד הסיבה הטכנית לוותר על היתרונות של React Native (קוד משותף, פיתוח מהיר, אקוסיסטם עשיר) לטובת פיתוח נייטיב טהור? לדעתי, כבר אין כזו.
Expo SDK 53 הפך את הארכיטקטורה החדשה לנגישה לכולם, עם הפעלה כברירת מחדל וכלים שמפשטים את חוויית הפיתוח. Reanimated 4 הביא את עולם האנימציות לרמה חדשה לגמרי עם CSS Animations ו-Worklets כמנוע מקביליות. ו-FlashList v2 הוכיח שרשימות ב-React Native יכולות להיות חלקות כמו בכל אפליקציה נייטיבית.
מה צפוי בהמשך?
כמה מגמות מעניינות באופק:
- Static Hermes — קומפילציה מקדימה (AOT) של JavaScript לקוד מכונה, שתשפר עוד יותר את זמני ההפעלה והביצועים. אני מחכה לזה כבר הרבה זמן.
- React Server Components ב-React Native — היכולת לרנדר קומפוננטות בצד השרת ולשלוח רק את ה-UI המוכן למכשיר. תחשבו מה זה יעשה לזמני טעינה.
- שיפורי Worklets — הרחבת יכולות ה-Worklets לתחומים נוספים כמו עיבוד אודיו בזמן אמת ו-Machine Learning.
- אינטגרציה עמוקה יותר עם Web APIs — תמיכה ביותר ויותר Web Standards, כולל Web Streams, Web Crypto ועוד.
אם עדיין לא ביצעתם מיגרציה לארכיטקטורה החדשה — עכשיו זה הזמן. באמת. הכלים בשלים, התיעוד מקיף, הקהילה תומכת, והתוצאות מדברות בעד עצמן.
התחילו היום: שדרגו את הפרויקט שלכם, הפעילו את הארכיטקטורה החדשה, ותגלו עולם חדש של ביצועים ויכולות. המשתמשים שלכם ירגישו את ההבדל — ואתם תרגישו אותו עוד יותר כמפתחים.