El duelo: React Native vs. Cordova

Publicado: 2022-03-11

Como resultado de la popularidad de los teléfonos inteligentes y las aplicaciones móviles, los desarrolladores web han estado buscando formas de crear aplicaciones móviles usando JavaScript. Esta popularidad resultó en el desarrollo de muchos marcos de JavaScript capaces de ejecutar aplicaciones nativas en dispositivos móviles. Actualmente, Cordova y React Native son las opciones más populares. Cordova es compatible con las plataformas móviles iOS, Android y Windows Phone. Con React Native, por otro lado, Android, iOS y UWP son objetivos para los desarrolladores. (UWP significa Universal Windows Platform, la plataforma de Microsoft que permite ejecutar la misma aplicación en Windows Phone 10 Mobile, XBox One y Windows 10).

Desde la superficie, parece que React Native y Cordova están ocupando el mismo espacio. Sin embargo, como ocurre con todas las tecnologías, hay aspectos en los que uno brilla y el otro se queda corto. Entonces, para obtener una mejor imagen de cada tecnología y conocer sus ventajas y desventajas, profundizaremos en los detalles de cada una y las compararemos en diferentes disciplinas.

Diferencias en Filosofía

Es importante recordar que el eslogan de React Native, "Aprende una vez, escribe en cualquier lugar" difiere del mantra multiplataforma habitual, "Escribe una vez, ejecuta en cualquier lugar". Esto lleva a dos cosas: en primer lugar, no podemos simplemente tomar nuestra base de código React existente de nuestro proyecto web y convertirla en una aplicación móvil con solo unos pocos clics. Sin embargo, React y React Native comparten muchos conceptos clave; un ejemplo son sus sistemas de componentes y, como resultado, React Native se siente instantáneamente familiar. Si bien React comparte muchas similitudes con React Native, existen algunas diferencias fundamentales, que van desde la forma en que se manejan las hojas de estilo hasta el tipo de componentes que podemos usar.

En segundo lugar, es posible que no podamos compartir el código React Native cuando nos dirigimos a diferentes plataformas. Esto sucede cuando preferimos que los elementos de la interfaz de usuario se comporten de forma nativa en su plataforma específica, lo que a su vez le brinda al usuario una mejor experiencia y una sensación más nativa de la aplicación. Un ejemplo obvio es el menú lateral del cajón en las aplicaciones de Android, que es muy poco común en las aplicaciones de iOS.

Córdoba no comparte esta filosofía. No es raro comenzar a desarrollar una aplicación web pura, luego empaquetarla como una aplicación Cordova y reutilizar la mayor cantidad de código posible para todas las plataformas (móviles) a las que queremos apuntar.

Libertad de desarrollo

En los dispositivos móviles, Cordova ejecuta una aplicación de una sola página dentro del navegador web móvil integrado, llamado WebView, y luego la empaqueta como una aplicación nativa. Si bien parece una aplicación nativa desde el exterior, nuestro código web se ejecuta dentro del motor del navegador móvil. Para nosotros, eso significa que no estamos atados a una biblioteca o marco específico. Si usamos JavaScript estándar, jQuery, Angular o cualquier otra cosa, cualquiera de esas opciones podría incluirse en una aplicación móvil con Cordova. Cordova no se impone en nuestra pila de tecnología. Mientras tengamos un archivo index.html , estamos listos para comenzar. Un ejemplo simple sería el siguiente fragmento de código:

 <html> <head> <title>My Cordova App</title> </head> <body> <div>Tap me</div> <script> // Select our element var element = document.getElementById('tapme'); // Send an alert once it was tapped/clicked element.addEventListener('click', function() { alert('Hello there!'); }); </script> </body> </html>

Este ejemplo significa que podemos usar prácticamente cualquier cosa que deseemos, como usar un administrador de paquetes como NPM o Bower, usar un transpilador como Babel, CoffeeScript o TypeScript, un paquete como Webpack o Rollup, o algo completamente diferente. No importa, siempre que el resultado sea un archivo index.html que cargue todo el JavaScript y las hojas de estilo que necesitamos.

React Native, como su nombre lo indica, se basa en React. Es importante comprender que la parte de React en React Native es una de sus características principales. Si no es un fanático de la naturaleza declarativa de React, incluido JSX, su componente y flujo de datos, es probable que no esté satisfecho con React Native. Si bien React Native se siente instantáneamente familiar para los desarrolladores de React, a primera vista, hay algunas diferencias para recordar. Con React Native no tenemos HTML ni CSS. En cambio, esta tecnología se centra en el lado de JavaScript. Como alternativa a CSS, los estilos se escriben en línea y Flexbox es el modelo de estilo predeterminado.

La aplicación React Native más básica sería similar a este ejemplo:

 // Import the React module for JSX conversion import { React } from 'react'; // Import React Native's components import { View, Text, AppRegistry, TouchableOpacity, } from 'react-native'; // Create an App component const App = () => { // Define our press handler const onPress = () => alert('Hello there!'); // Compose the components we are going to render return ( <View> <TouchableOpacity onPress={onPress} /> <Text>Tap me!</Text> </TouchableOpacity> </View> ); }; // Registers the `App` component as our main entry point AppRegistry.registerComponent('App', () => App);

React Native tiene su propio empaquetador. Agrupa todos los archivos de JavaScript en un archivo gigante, que luego es consumido y ejecutado por JavaScriptCore, el motor de JavaScript de Apple. JavaScriptCore se usa en iOS y Android, mientras que ChakraCore impulsa las aplicaciones React Native UWP. De manera predeterminada, React Native usa el transpilador de JavaScript Babel, lo que nos permite usar la sintaxis ECMAScript 2015+ (ECMAScript 6). Si bien no es necesario usar la sintaxis de ECMAScript 2015+, definitivamente se recomienda, ya que todos los ejemplos oficiales y los módulos de terceros la adoptan. Dado que React Native se ocupa del proceso de empaquetamiento y transpilación, nuestro código de aplicación y los módulos de terceros pueden aprovechar estas características sin necesidad de configurar las herramientas por nosotros mismos.

En resumen, React Native es un enfoque obstinado centrado en React para el desarrollo móvil, mientras que Cordova nos permite agrupar tecnologías web dentro del shell WebView.

Aspecto y sensación nativos

Una cosa que es importante para los usuarios es tener una apariencia nativa de una aplicación. Dado que las aplicaciones de Cordova suelen ser aplicaciones web simples, hay algunas cosas que pueden parecer extrañas al principio. Los problemas pueden variar desde la falta de retroalimentación visual en las áreas de pulsación, hasta el desplazamiento que no se siente tan suave como en las aplicaciones nativas, hasta un retraso de 300 milisegundos en los eventos de pulsación. Si bien existen soluciones para todos estos problemas, debemos recordar que es posible que debamos hacer un esfuerzo adicional si queremos que nuestra aplicación Cordova se parezca lo más posible a las aplicaciones nativas. En Cordova, no tenemos acceso a ningún control nativo. Si queremos tener una apariencia nativa, nos quedan dos opciones: volver a crear los controles nativos, como botones y elementos de entrada, con HTML y CSS, o implementar módulos nativos que accedan directamente a esos controles nativos. Podríamos hacerlo nosotros mismos o usando una biblioteca de terceros como Ionic u Onsen UI. Tenga en cuenta que es importante mantenerlos actualizados con las actualizaciones del sistema operativo a medida que se presenten. A veces, la apariencia de un sistema operativo móvil se renueva, como sucedió cuando se presentó iOS 7. Tener una aplicación que no se puede adaptar sacará a los usuarios de la experiencia. También podríamos recurrir a incluir complementos de Cordova que nos conecten con el lado nativo de las cosas. Uno de los controles nativos más completos es la biblioteca Ace de Microsoft.

Con React Native, por otro lado, tenemos acceso a controles nativos e interacción listos para usar. Los componentes como Text , TextInput o Slider se asignan a sus contrapartes nativas. Si bien algunos componentes están disponibles para todas las plataformas, otros componentes solo funcionan en plataformas específicas. Cuanto más queremos que nuestra aplicación tenga una apariencia nativa, más necesitamos usar componentes que solo están disponibles para esta plataforma específica y, por lo tanto, más diverge nuestra base de código. Las interacciones y gestos de contacto mental también son parte de React Native.

Comparación de rendimiento

Dado que Cordova solo tiene un WebView a su disposición, estamos sujetos a las limitaciones del WebView. Por ejemplo, después de su versión 4.0, Android finalmente comenzó a usar el motor Chrome (mucho más rápido) como WebView predeterminado. Mientras que con iOS, durante mucho tiempo la aplicación que se ejecutaba dentro del motor WebView predeterminado era significativamente más lenta que la misma aplicación en el navegador móvil Safari. Además, dado que JavaScript tiene un solo subproceso, es posible que tengamos problemas si hay demasiadas cosas sucediendo en el código de nuestra aplicación. Estas limitaciones conducen a animaciones lentas y es posible que nuestra aplicación no se sienta tan receptiva como nos gustaría que fuera. Si bien puede haber algunos trucos que podemos emplear aquí y allá, al final, estamos sujetos a los límites del navegador móvil.

React Native utiliza varios subprocesos, por lo que los elementos de la interfaz de usuario se ejecutan en su propio subproceso. Debido a que los componentes de React se vinculan a las vistas nativas, JavaScript no está haciendo el trabajo pesado en React Native.

Flujo de trabajo del desarrollador

Cordova ofrece una utilidad de línea de comandos para crear nuevas plantillas de proyectos, iniciar la aplicación en el simulador y construir la aplicación para el dispositivo real en un modo de producción. La mayoría de las veces, estamos desarrollando la aplicación en un navegador de escritorio y luego podemos empaquetarla como una aplicación móvil. Con la libertad que ofrece Cordova, debemos abordar el flujo de trabajo de desarrollo nosotros mismos. Si queremos recargar en vivo en el dispositivo, debemos implementarlo nosotros mismos. Para depurar aplicaciones de Cordova, aplicamos los mismos principios que se usan para depurar un sitio web. En iOS, por ejemplo, conectaríamos nuestro dispositivo móvil a través de USB, abriríamos Safari y sus herramientas para desarrolladores.

React Native ofrece una interfaz de línea de comandos similar y ofrece un flujo de trabajo de desarrollo familiar para los desarrolladores web. Obtenemos recarga en vivo fuera de la caja. Una vez que cambiamos un componente de React, nuestra aplicación se recarga con los cambios que hicimos. Una de las características más interesantes es el reemplazo de módulos en caliente, que recarga parcialmente los cambios en el componente que hicimos, sin alterar el estado de la aplicación. Incluso podríamos conectarnos a un dispositivo real y ver si nuestros cambios funcionan como esperaríamos en un dispositivo real. Nuestras aplicaciones React Native se pueden depurar de forma remota con Chrome for Desktop. El manejo de errores es obvio en React Native; si nos encontramos con un error, nuestra aplicación muestra un fondo rojo y se muestra el seguimiento de la pila. Gracias a sourcemaps, podemos ver la ubicación exacta del error. Cuando hacemos clic en él, nuestro editor de elección se abre en la ubicación precisa del código.

Extensibilidad y acceso a las características nativas

Desde el lado de JavaScript, somos libres de usar cualquier biblioteca de JavaScript, incluidos los paquetes de NPM. Sin embargo, debido a que React Native no es un entorno de navegador, es posible que nos resulte difícil utilizar código que se base en DOM. React Native adopta los módulos CommonJS y ES2015, por lo que cualquier biblioteca que use estos formatos es fácil de integrar.

Tanto Cordova como React Native tienen la capacidad de crear y usar complementos que se conectan al lado nativo de las cosas. Cordova proporciona una API de bajo nivel para crear la nuestra, lo que nos brinda mucho control, pero conduce al uso de más repeticiones nativas y de JavaScript.

Si tuviéramos que escribir hipotéticamente un complemento Cordova iOS en Objective-C, podría verse como el siguiente fragmento de código. Nuestro complemento solo registrará el parámetro de entrada.

 #import <Cordova/CDVPlugin.h> // Create a class that inherits from CDVPlugin @interface Log : CDVPlugin - (void)log:(CDVInvokedUrlCommand*)command; @end // The actual implementation of the class we just defined @implementation Log - (void)log:(CDVInvokedUrlCommand*)command { CDVPluginResult* pluginResult = nil; // We are getting all parameters and taking the first one NSString* echo = [command.arguments objectAtIndex:0]; // We are checking for the validity of the parameters if (echo != nil && [echo length] > 0) { // We are just printing the parameter using the native log method NSLog(echo); // Let's create a result for the plugin pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo]; } // Let's send a signal back with the plugin's result [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } @end

Para usar el módulo, esta pieza de código JavaScript ayudará:

 window.log = function(str, callback) { cordova.exec(callback, function(err) { callback('Nothing to echo.'); }, "Log", "log", [str]); };

Para usar el complemento, solo necesitamos llamar a la función log :

 window.log('Hello native!');

React Native, por otro lado, sigue una filosofía diferente; asigna automáticamente los tipos de JavaScript a sus contrapartes nativas al escribir complementos, lo que facilita la conexión del código nativo con JavaScript. Echemos un vistazo a un fragmento de código que es necesario para crear un módulo nativo con React Native:

 #import "RCTBridgeModule.h" @interface Log : NSObject <RCTBridgeModule> @end @implementation Log RCT_EXPORT_MODULE(); // This makes this method available NativeModules.Log.log RCT_EXPORT_METHOD(log:(NSString *)message) { NSLog(message); } @end

React Native vincula el módulo por nosotros con las llamadas RCT_EXPORT_MODULE y RCT_EXPORT_METHOD . Ahora podemos acceder a él con NativeModules.Log.log así:

 import { React } from 'react'; import { View, Text, AppRegistry, NativeModules TouchableOpacity, } from 'react-native'; // Create an App component const App = () => { // Log with our module once we tap the text const onPress = () => NativeModules.Log.log('Hello there'); return ( <View> <TouchableOpacity onPress={onPress} /> <Text>Tap me!</Text> </TouchableOpacity> </View> ); }; // Registers the `App` component as our main entry point AppRegistry.registerComponent('App', () => App);

Si bien solo analizamos de cerca la creación de un módulo en iOS con Objective-C, se aplican los mismos principios para crear un módulo para Android con Java.

Necesitamos vincular complementos nativos dentro de los archivos del proyecto para cada plataforma. Con iOS, por ejemplo, esto significa que debemos vincular la parte nativa compilada con nuestra aplicación y agregar los archivos de encabezado correspondientes. Este puede ser un proceso largo, especialmente si hay muchos módulos nativos. Afortunadamente, esto se simplifica significativamente mediante el uso de una utilidad de línea de comandos llamada rnpm que se ha convertido en parte de React Native.

Conclusión: ¿React Native o Cordova?

React Native y Cordova tienen diferentes propósitos y, por lo tanto, satisfacen diferentes necesidades. Por lo tanto, es difícil decir que una tecnología es mejor que otra en todas las disciplinas.

Al usar Cordova, puede convertir rápidamente su aplicación de una sola página existente en una aplicación móvil para diferentes plataformas, a costa de que las interacciones no tengan necesariamente la sensación nativa de su plataforma específica.

Con React Native, las aplicaciones tienen una apariencia más nativa, pero a costa de volver a implementar piezas de código para ciertas plataformas de destino. Si ya ha incursionado en React y está interesado en desarrollar aplicaciones móviles, React Native se siente como una extensión natural.

Relacionado: Inmersión en frío en React Native: un tutorial para principiantes