Blog de Obi Madu
Volver a todos los artículos
MobileSystem DesignInfrastructure

React Native y Expo: El modelo mental para entenderlo todo

Entiende cómo funcionan realmente React Native y Expo, desde las compilaciones nativas hasta las actualizaciones OTA y los flujos de desarrollo.

React Native y Expo: El modelo mental para entenderlo todo

React Native es increíblemente fácil de malinterpretar si vienes principalmente de un trasfondo de desarrollo web. Escribes componentes de React estándar, usas JavaScript o TypeScript, ejecutas un servidor de desarrollo que se siente familiar y obtienes capacidades de actualización increíblemente rápidas. Como el flujo de trabajo se siente tan cercano a crear React en la web, es extremadamente tentador pensar en React Native simplemente como una aplicación web pulcramente envuelta en una carcasa móvil.

Ese modelo mental es completamente erróneo.

React Native compila aplicaciones móviles nativas genuinas. La interfaz de usuario fundamentalmente no se renderiza en un DOM del navegador. No hay elementos div ni span, y ciertamente no hay ninguna página web oculta pretendiendo ser una aplicación. En cambio, tu código de React simplemente describe una interfaz nativa, y React Native actúa como el motor que convierte esa descripción en componentes reales de iOS y Android. Expo luego se construye sobre React Native suavizando los bordes históricamente ásperos del desarrollo móvil, proporcionando configuración nativa, compilaciones de desarrollo, enrutamiento basado en archivos, actualizaciones inalámbricas, compilaciones en la nube y acceso optimizado a APIs comunes del dispositivo. Una vez que entiendes profundamente el límite entre el entorno de ejecución nativo y el paquete de JavaScript, todo el ecosistema se vuelve significativamente menos confuso.

React Native no es React DOM

React para la web renderiza directamente en el DOM del navegador, mientras que React Native renderiza en primitivas de UI nativas proporcionadas por el sistema operativo.

React webReact Native
divView
span o pText
imgImage
DOM del navegadorVistas nativas de iOS y Android

Cuando escribes algo como esto:

<View style={{ backgroundColor: "red" }}>
  <Text>Hello</Text>
</View>

React Native no genera HTML por debajo. En iOS, crea vistas nativas de UIKit, y en Android, crea vistas nativas de Android. Esa distinción estructural importa inmensamente para el rendimiento, los estilos, la accesibilidad, los gestos, los módulos nativos y la implementación. No estás publicando un sitio web; estás publicando una aplicación nativa compilada cuyo comportamiento da la casualidad de que está impulsado por un motor de JavaScript.

Los dos programas dentro de cada aplicación de React Native

El concepto más crítico de asimilar en React Native es que tu aplicación en realidad son dos programas separados trabajando juntos sin problemas.

Tu aplicación móvil

Entorno de ejecución nativo <-> Paquete de JavaScript

El entorno de ejecución nativo es la aplicación compilada en sí. Está escrita en los lengajes nativos de la plataforma y construida estrictamente con herramientas nativas. En iOS, eso involucra Xcode, Swift y Objective-C. En Android, eso significa depender de Gradle, Kotlin y Java. Por el contrario, el paquete de JavaScript es el código real de tu aplicación React, que contiene tus pantallas, componentes, jerarquía de navegación, gestión de estados y toda la lógica de negocio subyacente.

El entorno de ejecución nativo alberga el motor de JavaScript, módulos nativos personalizados, permisos, metadatos de la aplicación, íconos de la app, pantallas de carga y el puente vital que permite que JavaScript converse con las APIs nativas. Está compilado, firmado, es específico de la plataforma y, lo que es crucial, no puede modificarse en el dispositivo de un usuario sin una actualización nativa formal a través de la tienda de aplicaciones. El paquete de JavaScript es mucho más flexible. Durante el desarrollo, puede cargarse sin problemas directamente desde tu computadora a través de una red local. En producción, normalmente se empaqueta de forma segura dentro del binario de la aplicación, pero con las actualizaciones inalámbricas, a menudo puede actualizarse sobre la marcha sin requerir una revisión completa en la tienda de aplicaciones.

La analogía del navegador suele ser útil aquí: el entorno de ejecución nativo es como el navegador Chrome, mientras que el paquete de JavaScript es como el sitio web. Puedes enviar actualizaciones a un sitio web de manera infinita sin requerir que el usuario actualice Chrome, pero si necesitas una función de navegador completamente nueva de la que Chrome carece, el navegador en sí deberá actualizarse inevitablemente.

Qué requiere realmente una reconstrucción nativa

Esta división fundamental explica una de las fuentes de fricción y confusión más comunes para los recién llegados: por qué algunos cambios se actualizan instantáneamente en la pantalla mientras que otros, de forma frustrante, requieren una reconstrucción nativa completa.

Cambio¿Necesita reconstrucción nativa?¿Posible actualización OTA?
Corregir texto de la UINo
Añadir una nueva pantallaNo
Corregir lógica de negocioNo
Añadir librería solo de JavaScriptNo
Añadir una librería nativaNo
Cambiar ícono de la appNo
Cambiar permisosNo

Si el cambio afecta exclusivamente a JavaScript, generalmente se puede refrescar instantáneamente y, por lo general, es apto para una actualización inalámbrica (OTA). Sin embargo, si el cambio afecta capacidades nativas del dispositivo, permisos del sistema, metadatos binarios o introduce nuevos módulos nativos, necesitas absolutamente una nueva compilación nativa. Dominar esa única regla explica casi todas las decisiones del flujo de trabajo de desarrollo en el ecosistema de React Native.

Lo que aporta Expo

Expo es una plataforma integral construida a propósito sobre React Native. Proporciona un entorno de desarrollo mucho más completo desde el principio y oculta hábilmente la gran mayoría de la complejidad de la compilación nativa hasta que realmente necesites interactuar con ella.

En un proyecto gestionado por Expo, rara vez ves las tradicionales carpetas ios/ y android/. En su lugar, configuras elegantemente el comportamiento nativo a través de app.json, app.config.js, plugins de configuración inteligentes y diversos paquetes instalados. Cuando finalmente llega el momento de compilar la aplicación, Expo puede generar limpiamente los proyectos nativos necesarios por ti mediante un solo comando:

npx expo prebuild

Ese poderoso comando crea los proyectos nativos ios/ y android/ basándose íntegramente en tu configuración de alto nivel y las dependencias enumeradas. Expo también ofrece módulos nativos ampliamente probados, excelentes herramientas de desarrollo, enrutamiento basado en archivos mediante Expo Router, EAS Build para compilaciones gestionadas en la nube, EAS Submit para envíos automatizados a tiendas de aplicaciones y EAS Update para desplegar actualizaciones inalámbricas de JavaScript. El punto fundamental no es que Expo borre el código nativo de la existencia: simplemente gestiona la complejidad de este en tu nombre.

Expo Go vs Compilaciones de Desarrollo

Expo Go es una aplicación precompilée sumamente conveniente y mantenida activamente por el equipo de Expo. La instalas directamente desde la tienda de aplicaciones, ejecutas npx expo start en tu máquina, escaneas un código QR con tu teléfono, y Expo Go carga al instante tu paquete de JavaScript. Es fenomenal para aprender React Native y prototipar ideas rápidamente, ya que no necesitas compilar nada de forma nativa antes de ver tu aplicación funcionando en un dispositivo físico.

La limitación principal es que Expo Go solo contiene los módulos nativos específicos que ya incluyó el equipo de Expo. Básicamente, no puedes probar en él cada dependencia nativa posible, comportamientos personalizados de íconos de la app, mecánicas de pantallas de carga en producción, enlaces universales o configuraciones complejas de notificaciones push remotas de manera nativa.

Una compilación de desarrollo es completamente diferente. Es el propio binario dedicado de tu app, explícitamente compilado para desarrollo, con la librería expo-dev-client instalada. Puedes imaginarlo fácilmente como tu propia versión personalizada de Expo Go. De hecho, incluye los módulos nativos específicos que tu app necesita legítimamente para funcionar en producción.

CaracterísticaExpo GoCompilación de desarrollo
ConfiguraciónInstalar desde la tiendaCompilar tu propia app
Librerías nativasLimitadas a los módulos de Expo GoCualquier librería nativa que incluyas
Ícono y pantalla de cargaNo es tu app finalLa configuración real de tu app
Notificaciones pushLimitadasPruebas realistas
Mejor usoAprendizaje y prototiposDesarrollo de apps serio

La regla práctica es notablemente sencilla: empieza con Expo Go si te brinda suficiente funcionalidad para tus necesidades actuales, pero cambia a compilaciones de desarrollo en el momento en que tu aplicación requiera un comportamiento nativo o bibliotecas de terceros que Expo Go simplemente no puede proporcionar.

Desarrollo y Producción cargan JavaScript de manera diferente

En un entorno de desarrollo, tu teléfono físico generalmente carga el paquete de JavaScript de forma continua desde Metro, que es el servidor de desarrollo local ejecutándose sin problemas en tu computadora.

Teléfono ejecutando Expo Go o una compilación de desarrollo
        |
        | solicita paquete de JavaScript
        v
Servidor de desarrollo Metro en tu computadora

Ese mecanismo es exactamente el motivo por el cual tu teléfono y tu computadora usualmente necesitan estar conectados exactamente a la misma red Wi-Fi. También es la razón subyacente por la que Fast Refresh funciona de maravilla: la aplicación está solicitando continuamente el código de un servidor de desarrollo activo.

En producción, la arquitectura cambia fundamentalmente. El paquete de JavaScript finalizado se empaqueta de forma segura dentro del binario de la aplicación.

TuApp.apk o TuApp.ipa
  código nativo
  assets
  main.jsbundle

Obviamente, la aplicación de producción no necesita conectarse a tu computadora local. Puede iniciarse sin problemas sin conexión, y el JavaScript está altamente optimizado y explícitamente empaquetado para el rendimiento. EAS Update introduce un modelo híbrido atractivo. La app se envía inicialmente con una versión de JavaScript empaquetada de manera segura en su interior, pero al iniciarse, puede buscar silenciosamente nuevas actualizaciones de JavaScript y almacenarlas dinámicamente en caché en el dispositivo. Esta capacidad es increíblemente potente para lanzar correcciones de errores y actualizaciones de interfaz de forma fluida, pero tiene un límite estricto e inflexible: las actualizaciones OTA absolutamente no pueden agregar nuevas capacidades o módulos nativos.

La estructura de un proyecto de Expo

Un proyecto gestionado por Expo suele estar estructurado para separar claramente el código JavaScript puro, la configuración nativa general, los activos estáticos y la configuración esencial de compilación.

tu-proyecto/
  app/              pantallas y rutas
  components/       UI reutilizable
  hooks/            hooks personalizados
  constants/        valores compartidos
  assets/           imágenes y fuentes
  app.json          configuración nativa de la app
  package.json      dependencias
  eas.json          configuración de compilación y actualización de EAS

El archivo app.json controla exhaustivamente los metadatos cruciales de la aplicación nativa.

{
  "expo": {
    "name": "My App",
    "slug": "my-app",
    "icon": "./assets/icon.png",
    "android": {
      "package": "com.company.myapp"
    },
    "ios": {
      "bundleIdentifier": "com.company.myapp"
    }
  }
}

El archivo package.json es de suma importancia porque las dependencias enumeradas en él pueden incluir frecuentemente módulos nativos. Instalar un paquete puramente de JavaScript e instalar un paquete que viene con código nativo son acciones fundamentalmente diferentes con implicaciones muy distintas para tu flujo de compilación.

React Native sigue siendo código Frontend

Si bien React Native puede hacer que una aplicación móvil se sienta increíblemente nativa, de ninguna manera convierte por arte de magia el código frontend en código backend. Una aplicación React Native nunca debería conectarse directamente a una base de datos de producción. No debe contener credenciales de base de datos en crudo, y jamás debe almacenar secretos privados de API dentro de su paquete. Cualquier persona puede inspeccionar de manera trivial los archivos APK e IPA, y los paquetes de JavaScript pueden ser extraídos fácilmente por actores malintencionados.

La arquitectura correcta y segura sigue siendo exactamente la misma que la mayoría de los sistemas frontend modernos:

App móvil <-> API Backend <-> Base de datos

La app móvil debería comunicarse estrictamente con tu API a través de HTTPS seguro. Luego, tu API maneja de manera segura la autenticación compleja, una autorización robusta, validación exhaustiva, limitación de velocidad estricta y el acceso privado a la base de datos. La base de datos permanece totalmente privada y oculta del cliente móvil. Exponer una URL de API en el código cliente es perfectamente normal, ya que los usuarios ya pueden interceptar y ver fácilmente el tráfico de red desde sus propios dispositivos. La seguridad genuina no proviene de ocultar la URL de la API; proviene por completo de una autenticación adecuada, autorización y la aplicación estricta de políticas del lado del servidor.

Las herramientas de Backend-as-a-service como Supabase y Firebase siguen adhiriéndose estrictamente a este patrón. El cliente se comunica de forma segura con una capa de API intermediaria, sin utilizar nunca directamente las credenciales de la base de datos con acceso ilimitado. Por ejemplo, la clave pública "anon" de Supabase está diseñada explícitamente para estar expuesta de manera segura al cliente, pero debe emparejarse inevitablemente con la autenticación adecuada y estrictas políticas de seguridad a nivel de fila en el lado de la base de datos.

const supabase = createClient(
  "https://xyz.supabase.co",
  "public-anon-key"
);

const { data } = await supabase
  .from("interviews")
  .select("*");

La seguridad subyacente proviene intrínsecamente de las estrictas políticas que se ejecutan activamente detrás de la API, y no de fingir que la clave en el lado del cliente es un secreto celosamente guardado.

El modelo mental a conservar

En última instancia, React Native es simplemente un contenedor nativo que ejecuta una aplicación JavaScript sumamente capaz. Expo actúa como la plataforma robusta que hace que ese contenedor sea significativamente más fácil de configurar, compilar, actualizar fluidamente y, finalmente, enviar a los usuarios. Expo Go es un contenedor precompilado compartido de gran utilidad, mientras que una compilación de desarrollo actúa como tu propio contenedor totalmente personalizado. Una actualización OTA altera únicamente el JavaScript que se ejecuta dentro de ese contenedor, por separado del contenedor en sí.

Una vez que ves y respetas claramente ese límite, todo el ecosistema cobra mucho más sentido. Entiendes instintivamente por qué agregar una nueva pantalla es instantáneo, por qué agregar una librería nativa exige una compilación nueva, por qué Expo Go eventualmente deja de ser suficiente para apps complejas, y por qué las apps móviles invariablemente siguen necesitando un backend seguro y dedicado. Esa es toda la curva de aprendizaje de React Native y Expo condensada en un solo concepto global: comprende qué vive de forma segura en JavaScript, qué vive estrictamente en el código nativo, y exactamente qué cruza el límite crítico entre ambos.

Referencias