Новая архитектура React Native: Fabric, TurboModules и JSI
Продвинутое3 минРедакция Innovialabs
Коротко
Новая архитектура заменяет асинхронный bridge с JSON-сериализацией прямыми вызовами через JSI: нативные модули грузятся лениво и типизируются через Codegen, а рендерер Fabric поддерживает конкурентные возможности React. Миграция начинается с аудита зависимостей.
Что изменилось и зачем
В старой архитектуре JavaScript и нативный код общались через bridge: каждое сообщение сериализовалось в JSON, складывалось в очередь и передавалось асинхронно. Это работало, но имело ограничения:
- накладные расходы на сериализацию при частом обмене данными;
- все вызовы асинхронные — нельзя синхронно спросить что-то у нативной стороны;
- все нативные модули инициализировались при старте, даже если не нужны;
- рендерер не умел работать с конкурентными возможностями React.
Новая архитектура состоит из трёх частей, которые снимают эти ограничения.
Три составляющие
JSI (JavaScript Interface) — C++ API, через который JavaScript-движок держит прямые ссылки на нативные объекты и вызывает их методы. Без JSON и без очереди. Вызовы могут быть синхронными, когда это оправдано.
TurboModules — новая система нативных модулей поверх JSI:
- модули загружаются лениво, при первом обращении;
- интерфейс описывается в TypeScript или Flow, а Codegen генерирует нативные заготовки — несоответствие типов ловится на сборке, а не в рантайме.
Fabric — новый рендерер, ядро которого написано на C++ и общее для iOS и Android. Он умеет синхронно измерять и обновлять разметку и поддерживает конкурентный рендеринг React: Suspense, transitions, корректный useLayoutEffect.
Вместе с ними пришёл bridgeless-режим, в котором старый bridge не создаётся вовсе. В свежих версиях React Native новая архитектура включена по умолчанию, а старая постепенно выводится из поддержки.
Где ощущается выигрыш
Конкретные цифры зависят от приложения, поэтому смотрите на механизмы:
- Старт приложения — модули не инициализируются все сразу.
- Частый обмен данными с нативом (жесты, анимации, сенсоры, работа с файлами) — нет затрат на сериализацию.
- Отзывчивость интерфейса — срочные обновления не ждут тяжёлого рендера благодаря конкурентным возможностям.
- Синхронные операции вроде измерения элемента перед показом подсказки — без мерцания.
Если приложение в основном показывает списки из API, разница может быть незаметной. Проверяйте профилированием на реальных устройствах и release-сборках.
Как выглядит модуль с Codegen
Спецификация TurboModule на TypeScript:
// specs/NativeDeviceInfo.ts
import type { TurboModule } from "react-native";
import { TurboModuleRegistry } from "react-native";
export interface Spec extends TurboModule {
getDeviceName(): string;
getBatteryLevel(): Promise<number>;
}
export default TurboModuleRegistry.getEnforcing<Spec>("DeviceInfo");
Codegen подключается в package.json:
"codegenConfig": {
"name": "AppSpecs",
"type": "modules",
"jsSrcsDir": "specs",
"android": { "javaPackageName": "com.example.app" }
}
После этого нативную реализацию пишут на Kotlin/Java и Objective-C++/Swift по сгенерированным интерфейсам.
Шаги миграции существующего приложения
- Аудит зависимостей. Составьте список всех библиотек с нативным кодом и проверьте их статус в React Native Directory или в репозиториях.
- Обновление React Native до актуальной версии. Делайте это по шагам и сверяйтесь с Upgrade Helper — прыжок через много версий сразу усложняет поиск проблем.
- Включение архитектуры, если в вашей версии она ещё не включена по умолчанию:
newArchEnabled=trueвandroid/gradle.properties, для iOS — переустановка pods с новой архитектурой; в Expo — соответствующий флаг в конфиге приложения. - Перенос собственных модулей на TurboModules и собственных нативных компонентов на Fabric: спецификация, Codegen, реализация.
- Тестирование обеих платформ в release-режиме: навигация, жесты, клавиатура, модальные окна, сторонние SDK.
- Поэтапный выпуск — staged rollout в сторах и мониторинг крашей.
Совместимость библиотек
Это главный риск миграции.
- Interop-слой позволяет многим старым модулям и компонентам работать без переписывания, но не всем и не всегда идеально.
- Ломаются чаще всего библиотеки, которые напрямую обращаются к объекту bridge, используют
setNativePropsили нестандартные приёмы работы сUIManager. - Заброшенные библиотеки — повод заменить их на поддерживаемые аналоги, сделать форк или написать небольшой модуль самостоятельно.
- Обновляйте библиотеки до версий с явной поддержкой новой архитектуры до переключения, а не после.