Kiến Trúc Mới React Native 2026: Migrate Sang Fabric, TurboModules Và Bridgeless Mode
Hướng dẫn migrate React Native từ kiến trúc cũ sang Fabric, TurboModules và Bridgeless Mode trên RN 0.83 (2026). Code examples, footgun và cách đo hiệu năng từ kinh nghiệm sáu app production.
Kiến Trúc Mới (New Architecture) của React Native là bộ render và module gốc thế hệ mới gồm Fabric, TurboModules, JSI và Bridgeless Mode. Từ React Native 0.76 trở đi nó đã là mặc định, và đến 2026 (RN 0.83) gần như mọi thư viện phổ biến đều đã hỗ trợ. Nếu bạn đang chạy 0.74 hoặc cũ hơn, đây là thời điểm hợp lý nhất để migrate. Bài này mình đi qua đúng các bước mình đã làm khi đưa sáu app production sang Bridgeless Mode, cộng với những thư viện hay gãy và cách xử lý qua Interop Layer.
Kiến Trúc Mới đã là mặc định từ React Native 0.76 (cuối 2024) và ổn định trên 0.83 (2026); bạn không còn phải bật cờ newArchEnabled nữa.
Bốn thành phần cốt lõi: Fabric (renderer mới), TurboModules (native modules đồng bộ qua JSI), Codegen (type-safe binding) và Bridgeless Mode (xoá bỏ asynchronous bridge cũ).
Migration thực tế tốn 1–3 ngày cho app vừa nếu dependency đã tương thích, hoặc 1–2 tuần nếu bạn còn dùng native module legacy chưa migrate.
Interop Layer cho phép chạy module/component cũ kiểu legacy bên trong Bridgeless Mode, nên đừng vội rewrite mọi thứ. Hãy migrate dần.
Lợi ích đo được trên app mình ship: thời gian khởi động giảm 15–25%, animation 120fps mượt hơn rõ rệt, và bug race-condition khi gọi UI sync biến mất.
Có một số footgun thật: findNodeHandle bị deprecated, setNativeProps không còn hoạt động cho component Fabric, và một vài thư viện animation cũ vẫn dùng Paper renderer.
Kiến Trúc Mới React Native là gì?
Kiến Trúc Mới (New Architecture) là tổ hợp bốn công nghệ mà team Meta đã làm trong gần năm năm để thay thế lớp bridge bất đồng bộ vốn là gốc rễ của hầu hết bug khó debug trong React Native. Nó gồm JSI (JavaScript Interface, kênh giao tiếp trực tiếp giữa JS engine và C++/native, thay cho serialize JSON qua bridge), Fabric (UI renderer mới chạy đồng bộ và hỗ trợ concurrent rendering của React 19), TurboModules (native module gọi sync, lazy-load, type-safe) và Bridgeless Mode (xoá hẳn lớp bridge cũ ra khỏi bundle).
Theo thông báo chính thức của Meta tháng 10/2024, Kiến Trúc Mới đã trở thành mặc định từ phiên bản 0.76. Trên React Native 0.83 (release tháng 4/2026 trong Expo SDK 55), cờ newArchEnabled đã được bỏ, nghĩa là bạn phải opt-out chứ không opt-in nữa. Điều này có nghĩa: nếu bạn ở 0.74 hoặc cũ hơn và đang lên kế hoạch nâng cấp, đây không còn là "thử nghiệm". Đây là đường đi mặc định của cả ecosystem.
Mình bullish vào hướng đi này, nhưng không lãng mạn về chi phí migration. Trong sáu app mà mình đã ship, migration nhanh nhất mất một ngày rưỡi (app Expo managed thuần, chỉ có thư viện chính thức), chậm nhất mất hơn hai tuần (app có ba native module tự viết và một SDK third-party đã ngừng bảo trì). Bài viết này sẽ phản ánh đúng phổ đó. Honestly, nếu bạn đang ở khoảng giữa thì 4–6 ngày là con số mình hay quote cho team product.
Fabric, TurboModules, JSI và Bridgeless: vai trò từng thành phần
Nhiều đội nhầm bốn cái tên này là tuỳ chọn riêng lẻ. Thực tế chúng là bốn tầng của cùng một stack. Bạn không bật được TurboModules nếu không có JSI, và Bridgeless Mode chỉ có nghĩa khi cả Fabric lẫn TurboModules đã chạy.
JSI (JavaScript Interface)
JSI là cái nền. Nó là một API C++ cho phép JS engine (Hermes, JSC, hoặc V8) tham chiếu trực tiếp tới object native như là một HostObject, không cần serialize qua JSON. Mọi thứ phía trên (Fabric, TurboModules, React Native Reanimated worklets, MMKV) đều build trên JSI. Bạn không cấu hình JSI trực tiếp; nó được bật cùng Hermes.
Fabric
Fabric là renderer mới, viết lại bằng C++. Khác biệt lớn nhất so với Paper (renderer cũ): commit phase đồng bộ trên main thread, nên React 19 concurrent features (Suspense, transitions, useDeferredValue) hoạt động đúng nghĩa. Fabric cũng là điều kiện bắt buộc để Reanimated 4 chạy CSS-style animations. Mình có viết riêng về điều này trong bài Reanimated 4 trên New Architecture.
TurboModules
TurboModules thay thế NativeModules cũ. Ba thay đổi quan trọng: (1) gọi sync, không còn callback/Promise giả tạo cho các call lẽ ra phải đồng bộ; (2) lazy-load, module chỉ được khởi tạo khi JS thực sự gọi tới, giảm cold start; (3) type-safe qua Codegen, spec viết bằng TypeScript hoặc Flow được generate ra Objective-C/Java header tự động.
Bridgeless Mode
Bridgeless Mode là dấu chấm hết của lớp bridge bất đồng bộ. Khi bạn bật nó, runtime không còn khởi tạo RCTBridge nữa; mọi thứ đi qua ReactInstance mới. Đây là chế độ mặc định trên 0.76+ và là tiền đề để Meta tiếp tục cải thiện startup time với React Native DevTools và preload bundles.
Khía cạnh
Kiến Trúc Cũ (Paper + Bridge)
Kiến Trúc Mới (Fabric + Bridgeless)
Giao tiếp JS ↔ Native
JSON serialize qua bridge
JSI tham chiếu trực tiếp
Native module call
Bất đồng bộ, eager-load
Đồng bộ tuỳ chọn, lazy-load
UI commit
Bất đồng bộ, three-thread model
Đồng bộ trên main thread
React 19 concurrent
Không tận dụng được
Hỗ trợ đầy đủ Suspense, transitions
Cold start trung bình
Baseline
Giảm 15–25% (đo trên app mình)
Type safety binding
Tự viết tay
Codegen tự động từ TS spec
Status 2026
Deprecated, sẽ gỡ ở 0.85+
Mặc định từ 0.76
Kiểm tra trước khi migrate: dependency và phiên bản
Bước đầu tiên không phải là sửa code, mà là dựng bảng kiểm dependency. Mở package.json và check từng thư viện trên reactnative.directory với filter "New Architecture" bật. Đây là source of truth được community maintain. Mỗi thư viện sẽ có ba trạng thái: hỗ trợ đầy đủ, hỗ trợ qua interop, hoặc chưa hỗ trợ.
Sau khi audit xong, đảm bảo các yêu cầu sau:
React Native ≥ 0.76, phiên bản đầu tiên New Architecture là default. Khuyến nghị 0.83+ để có Bridgeless ổn định.
React 19.0+ đi kèm RN 0.76. Trên 0.83 là React 19.1.
Sau đó chạy npx expo prebuild --clean để regenerate ios/ và android/ với cấu hình mới, rồi npx expo run:ios hoặc build qua EAS.
Bare React Native workflow
Trên bare workflow (không Expo), bật New Architecture bằng cách:
# android/gradle.properties
newArchEnabled=true
# ios/Podfile.properties.json
{
"newArchEnabled": "true"
}
# Sau đó:
cd ios && bundle exec pod install && cd ..
npx react-native run-ios
Trên RN 0.83, newArchEnabled đã có giá trị mặc định là true nên bạn có thể bỏ luôn dòng đó. Mình giữ lại trong codebase chỉ để rõ ràng cho người mới vào project.
Xử lý thư viện chưa tương thích qua Interop Layer
Đây là phần làm mình mất nhiều thời gian nhất trong app thứ hai. Interop Layer là cơ chế Meta thêm vào để chạy native module/component kiểu legacy bên trong runtime mới. Bạn không phải làm gì cả, nó tự động kích hoạt khi runtime phát hiện một module chưa migrate. Nhưng có hai cạm bẫy.
Một: module qua Interop Layer KHÔNG có ưu điểm sync call và lazy-load. Nó vẫn đi qua một dạng bridge mô phỏng. Nghĩa là bạn không thể vừa tự hào "đã chạy Bridgeless" vừa ngầm phụ thuộc vào một SDK quảng cáo cũ chạy interop. Performance numbers sẽ không cải thiện cho phần đó.
Hai: nếu thư viện legacy đó tạo view (component, không phải module), bạn phải khai báo trong react-native.config.js để Fabric biết:
Quên bước này thì view sẽ render trắng trên iOS hoặc crash UnimplementedView trên Android. Đây là lỗi mình gặp nhiều nhất khi review PR migration của các đội khác.
Viết TurboModule đầu tiên với Codegen
Nếu bạn maintain native module riêng, đây là lúc rewrite sang TurboModule. Quy trình ngắn hơn so với native module cũ vì Codegen lo phần binding.
Bước 1, viết spec TypeScript:
// modules/DeviceMetrics/src/NativeDeviceMetrics.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
getBatteryLevel(): number; // gọi sync, trả về 0..1
getDeviceId(): string;
setHapticEnabled(enabled: boolean): void;
readonly getConstants: () => {
osVersion: string;
isTablet: boolean;
};
}
export default TurboModuleRegistry.getEnforcing<Spec>('DeviceMetrics');
Lưu ý getTurboModule, đây là entry point Codegen sinh ra header cho. Bên Android, bạn extend NativeDeviceMetricsSpec (class abstract Codegen sinh ra trong build/generated/source/codegen) thay vì ReactContextBaseJavaModule như trước.
Codegen chạy tự động khi build. Để debug binding, chạy npx react-native codegen và inspect output trong build/generated/. React Native New Architecture Working Group trên GitHub là nơi tốt nhất để theo dõi thay đổi API và workaround.
Footgun và lỗi thường gặp khi chuyển sang Fabric
Đây là danh sách những thứ đã làm mình mất ngủ, kèm cách xử lý.
findNodeHandle và setNativeProps không còn hoạt động
Trong Paper bạn có thể grab handle node rồi gọi setNativeProps để bypass React. Fabric không cho, vì render tree là immutable per commit. Cách thay thế: dùng ref + state, hoặc với scroll/text input dùng commands API mới qua UIManager.dispatchViewManagerCommand. Reanimated worklets thay thế gần hết use case "imperative animation".
Layout effects chạy sync hơn
Fabric commit đồng bộ nên onLayout firing pattern thay đổi. Mình từng có code rely vào việc onLayout chạy sau paint frame đầu để measure. Trên Fabric nó chạy ngay trong commit, gây ra một loop set-state infinite. Fix: dùng useLayoutEffect hoặc check dimension trước khi setState. (Mình hit đúng bug này lúc ship feature pull-to-refresh có animated header.)
Hermes bytecode cache invalidation
Khi bạn upgrade từ Paper sang Fabric, bytecode cache cũ vẫn còn trên thiết bị test. Triệu chứng: dev build chạy ngon, EAS preview crash ngay launch. Fix: xoá app khỏi thiết bị trước khi cài bản mới, hoặc bump bundle version.
Một số thư viện animation legacy vẫn dùng Paper
Cụ thể: phiên bản cũ của Lottie, Skia trước v1.0, vài chart library. Nâng cấp lên phiên bản mới nhất, hoặc tạm khai báo qua unstable_reactLegacyComponentNames.
Đo lường hiệu năng trước và sau migration
Migrate xong mà không đo thì sếp khó approve effort. Mình dùng ba metric:
Time-to-interactive (TTI): thời gian từ khi user tap icon đến khi first screen interactive. Đo bằng react-native-performance hoặc Firebase Performance. App e-commerce mình ship: 2.1s xuống 1.6s.
JS frame rate trong scroll-heavy screens: đo bằng React Native DevTools profiler. Vào màn hình list với 200+ items, scroll fast 5 giây, ghi nhận avg fps. Trên Fabric thường thấy improvement rõ nhất ở list dày + animation đồng thời.
Cold start CPU samples: dùng Xcode Instruments hoặc Android Studio Profiler để xem có bao nhiêu native module được khởi tạo trong 500ms đầu. Trước migration: 23 module. Sau (vì lazy-load): 6 module. Đây là nguồn gốc của improvement TTI.
Để hiểu sâu hơn cách đo và tune ba metric này, bài tối ưu hiệu suất React Native 2026 đi chi tiết hơn về profiler workflow và FlashList. Đừng chỉ dựa vào "cảm giác mượt hơn"; số liệu là cái duy nhất bảo vệ được effort migration trong retro.
Câu hỏi thường gặp
Tôi có bắt buộc phải migrate sang New Architecture không?
Bắt buộc nếu bạn đang ở RN 0.76+ vì đó là mặc định. Trên 0.74 hoặc cũ hơn bạn vẫn chạy được, nhưng community đang dần ngừng hỗ trợ Paper. Reanimated 4, Skia v2 và Expo Router v6 đều yêu cầu New Architecture. Đợi thêm 6 tháng nữa bạn sẽ bị kẹt với dependency cũ.
Bridgeless Mode khác gì New Architecture?
Bridgeless Mode là tầng cuối cùng của New Architecture, nó tắt hẳn lớp bridge bất đồng bộ cũ. Bạn có thể bật Fabric + TurboModules mà vẫn giữ bridge (chế độ trung gian), nhưng từ RN 0.76 Bridgeless là mặc định và không có lý do thực tế nào để tắt nó trừ khi đang debug interop layer.
Migration mất bao lâu cho app cỡ trung bình?
Theo kinh nghiệm sáu app của mình: 1–3 ngày nếu chỉ dùng thư viện chính thức và Expo modules; 1–2 tuần nếu có 2–3 native module tự viết cần rewrite sang TurboModule; 2–4 tuần nếu phụ thuộc SDK third-party đã ngừng bảo trì (lúc đó phải fork hoặc thay thế).
Tôi có thể chạy đồng thời cả module mới và module cũ không?
Có, đó chính là chức năng của Interop Layer. Module/component legacy vẫn chạy được trong runtime Bridgeless thông qua một adapter tự động. Nhưng nhớ rằng các module qua interop không hưởng lợi sync call và lazy-load; chúng vẫn chậm như cũ.
Codegen có bắt buộc khi viết TurboModule không?
Bắt buộc. TurboModule không có khái niệm "tự khai báo binding bằng tay" như NativeModules cũ. Bạn viết spec TypeScript hoặc Flow, Codegen sinh ra header iOS/Android tại build time, và bạn implement theo header đó. Cách này khoá type safety và là điều kiện tiên quyết cho sync call.
Sau khi bật New Architecture, app crash ở launch, debug từ đâu?
90% trường hợp là do một native module/component cũ chưa được khai báo trong unstable_reactLegacyComponentNames hoặc thư viện thực tế chưa hỗ trợ. Mở Xcode log hoặc adb logcat, tìm dòng có UnimplementedView hoặc TurboModule not found. Tên class trong log chỉ ra đúng module cần khai báo legacy hoặc upgrade.
Bộ ba EAS Build, EAS Submit và EAS Update giúp bạn deploy React Native lên App Store và Google Play năm 2026 mà không cần Mac riêng. Hướng dẫn cấu hình eas.json, runtimeVersion, OTA và CI/CD GitHub Actions với ví dụ thực tế.
Hướng dẫn triển khai push notifications React Native 2026 với expo-notifications, FCM v1 HTTP API và APNs HTTP/2: cấu hình credentials, đăng ký token, background handler, deep linking và troubleshooting các lỗi thường gặp.