Vicen Moreno

Pro Googler

Follow me on GitHub

React Native New Architecture - Fabric y TurboModules en producción

Después de años de espera, la nueva arquitectura de React Native está lista

El contexto

React Native 0.74+ trae la nueva arquitectura habilitada por defecto. Después de años de desarrollo, Fabric y TurboModules están listos para producción.

Migramos una app de 100k usuarios. Aquí está nuestra experiencia.

¿Qué es la nueva arquitectura?

Arquitectura vieja (Bridge)

JavaScript ←→ Bridge (JSON) ←→ Native
              (asíncrono, serialización)

Problemas:

  • Serialización JSON lenta
  • Comunicación asíncrona obligatoria
  • No puede compartir memoria

Arquitectura nueva

JavaScript ←→ JSI ←→ Native
              (síncrono, memoria compartida)

Componentes:

  • JSI (JavaScript Interface): C++ layer para comunicación directa
  • Fabric: Nuevo sistema de renderizado
  • TurboModules: Módulos nativos con lazy loading
  • Codegen: Generación de código type-safe

Habilitando la nueva arquitectura

React Native 0.74+

// react-native.config.js
module.exports = {
  project: {
    ios: {},
    android: {},
  },
};
# ios/Podfile
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
# android/gradle.properties
newArchEnabled=true
cd ios && pod install
cd android && ./gradlew clean

Migración de componentes nativos a Fabric

Componente viejo (Paper)

// Android - MyViewManager.java
public class MyViewManager extends SimpleViewManager<MyView> {
    @Override
    public String getName() {
        return "MyView";
    }

    @ReactProp(name = "color")
    public void setColor(MyView view, String color) {
        view.setBackgroundColor(Color.parseColor(color));
    }
}

Componente nuevo (Fabric)

// MyView.ts - Spec file
import type { ViewProps } from 'react-native';
import type { HostComponent } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';

interface NativeProps extends ViewProps {
  color?: string;
}

export default codegenNativeComponent<NativeProps>('MyView') as HostComponent<NativeProps>;
// Android - MyViewManager.java (actualizado)
@ReactModule(name = MyViewManager.NAME)
public class MyViewManager extends SimpleViewManager<MyView>
    implements MyViewManagerInterface<MyView> {

    public static final String NAME = "MyView";

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    @ReactProp(name = "color")
    public void setColor(MyView view, @Nullable String color) {
        if (color != null) {
            view.setBackgroundColor(Color.parseColor(color));
        }
    }
}

Migración de módulos nativos a TurboModules

Módulo viejo

@ReactModule(name = "Calculator")
public class CalculatorModule extends ReactContextBaseJavaModule {
    @ReactMethod
    public void add(double a, double b, Promise promise) {
        promise.resolve(a + b);
    }
}

TurboModule

// NativeCalculator.ts - Spec
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  add(a: number, b: number): Promise<number>;
  // Métodos síncronos ahora posibles!
  multiply(a: number, b: number): number;
}

export default TurboModuleRegistry.getEnforcing<Spec>('Calculator');
// CalculatorModule.java
public class CalculatorModule extends NativeCalculatorSpec {
    @Override
    public void add(double a, double b, Promise promise) {
        promise.resolve(a + b);
    }

    // ¡Método síncrono! Imposible con bridge viejo
    @Override
    public double multiply(double a, double b) {
        return a * b;
    }
}

Codegen

Genera código C++ automáticamente desde specs TypeScript:

# Generar código
cd android && ./gradlew generateCodegenArtifactsFromSchema

# Archivos generados en:
# android/app/build/generated/source/codegen/

Performance: Antes vs Después

Benchmarks en nuestra app:

Startup time

Vieja arquitectura: 2.8s
Nueva arquitectura: 1.9s (-32%)

Lista con 1000 items (scroll FPS)

Vieja arquitectura: 45 FPS (drops a 20)
Nueva arquitectura: 58 FPS (estable)

Llamadas nativas

Vieja (Bridge): 0.5ms por llamada
Nueva (JSI): 0.02ms por llamada (-96%)

Memory

Vieja arquitectura: 180MB
Nueva arquitectura: 145MB (-19%)

Problemas encontrados

1. Librerías no compatibles

Error: TurboModuleRegistry.getEnforcing(...): 'OldLibrary' could not be found

Solución: Actualizar librería o usar interop layer:

// Para librerías viejas que no soportan TurboModules
// React Native incluye interop automático

2. Crashes en shadow nodes

Fatal: Attempt to access ShadowNode that no longer exists

Causa: Componente custom mal migrado a Fabric.

Solución: Revisar lifecycle del componente nativo.

3. Reanimated issues

# Versión compatible
npm install react-native-reanimated@3.6.0

Reanimated 3.x es compatible con nueva arquitectura.

4. Hermes obligatorio

Nueva arquitectura requiere Hermes:

# ios/Podfile
:hermes_enabled => true

Librerías compatibles

Compatibles:

  • react-native-reanimated 3.x
  • react-native-gesture-handler 2.x
  • react-native-screens 3.x
  • react-native-svg 14.x
  • @react-navigation/* 6.x

⚠️ Parcialmente compatibles:

  • Algunas librerías con interop layer

No compatibles:

  • Librerías sin mantenimiento activo
  • Librerías con bridge muy custom

Estrategia de migración

Fase 1: Preparación (2 semanas)

# Actualizar React Native
npx react-native upgrade 0.74.0

# Actualizar dependencias
npm update

# Verificar compatibilidad
npx react-native-new-arch-helper

Fase 2: Habilitar en desarrollo (1 semana)

# android/gradle.properties
newArchEnabled=true

Testing exhaustivo en desarrollo.

Fase 3: Migrar módulos custom (2-4 semanas)

Migrar nuestros módulos nativos a TurboModules.

Fase 4: Beta con usuarios reales (2 semanas)

Release a 10% de usuarios, monitorear crashes.

Fase 5: Rollout completo

100% de usuarios.

Monitoreo post-migración

// Crashlytics custom attributes
import crashlytics from '@react-native-firebase/crashlytics';

crashlytics().setAttribute('architecture', 'new');

// Comparar crash rates entre arquitecturas

¿Vale la pena migrar?

Sí, si:

  • Tienes problemas de performance
  • Mantienes módulos nativos propios
  • Planeas largo plazo con React Native

Espera, si:

  • App funciona bien actualmente
  • Dependes de librerías no actualizadas
  • No tienes tiempo para testing exhaustivo

Resultados en producción

Después de 3 meses con nueva arquitectura:

  • Crash rate: 0.8% → 0.5%
  • ANRs (Android): -40%
  • User complaints performance: -60%
  • App Store rating: 4.2 → 4.5

La migración tomó 6 semanas pero valió cada hora invertida.

¿Has migrado a la nueva arquitectura? ¿Qué problemas encontraste?


 Anterior      Posterior

Por Vicente José Moreno Escobar el 3 de junio de 2024
Archivado en: React Native   Mobile   Performance



Puedes disfrutar de otros artículos como éste en el archivo del sitio.