React Native: aplicación y crítica

Con mayor frecuencia al elegir este idioma, se espera que el desarrollo de una aplicación para dos plataformas demore la mitad del tiempo que el desarrollo de dos aplicaciones. Pero al final resulta que el desarrollo requiere tanto, si no más, debido a las dificultades ocultas bajo el brillo exterior y el marketing. Hablaremos sobre algunas de las dificultades similares que hemos encontrado en los últimos meses de trabajo con React Native.


React Native adapta Javascript para el desarrollo móvil. Esto se logra por el hecho de que utiliza varios recopiladores para construir proyectos: Metro Bundler, que interpreta el código JS y representa los recursos y el recopilador del sistema de destino. En nuestro caso, fue un gradle para Android. En teoría, la aplicación React Native debería comenzar de manera bastante simple. El comando react-native run-android habilita Metro Bundler y construye la aplicación para todos los dispositivos y emuladores Android conectados.


En realidad, resultó que incluso en esta etapa hay dificultades. Un error "No se puede descargar el paquete JS" apareció constantemente en nuestro proyecto, lo que significaba que el paquete no podía traducir el código al nativo. Como resultó más tarde, debido al hecho de que no comenzó. StackOverflow confirmó las conjeturas y sugirió que debería ejecutar bundler en un hilo separado usando el comando de inicio react-native. Esto le permite reiniciar el paquete solo si package.json ha cambiado, porque el procedimiento no ralentiza mucho el desarrollo.


Package.json es un archivo que contiene un conjunto de módulos externos para la aplicación. En npmjs.com hay una gran cantidad de bibliotecas diferentes para React Native, ampliando la funcionalidad y simplificando el desarrollo. Muchas bibliotecas (por ejemplo, Firebase) usan funciones nativas y, por lo tanto, deben asociarse directamente con el código nativo. Para hacer esto, use el comando react-native link <library-name>, que debe configurar estas relaciones con el código nativo.


Debido al hecho de que todas las bibliotecas están escritas en diferentes momentos, usan diferentes versiones del SDK y requieren un enfoque diferente. A veces sucede que las bibliotecas son incompatibles entre sí, o la última versión de la biblioteca es experimental, y los propios desarrolladores aconsejan que se baje a la penúltima. Muy a menudo, el enlace no configura todas las dependencias requeridas. Entonces, para la base de fuego mencionada anteriormente, debe agregar muchas bibliotecas adicionales en el código nativo, conectar varios repositorios externos, modificar mainApplication.java (¡y esto es solo para Android!). Para Firebase, hay una instrucción bastante comprensible para realizar estas acciones, pero para otras bibliotecas no siempre está presente.


Después de configurar las conexiones con el código nativo, puede compilar el proyecto con la esperanza de que la biblioteca conectada funcione. Al ensamblar, vale la pena recordar que si obtiene un error, debe asegurarse de que surgió precisamente debido a sus acciones, y no debido a un error del recopilador. Para una total confianza, debe realizar la siguiente secuencia de acciones:


rmdir node_modules /s /q && npm cache clean - force && npm i 

Este comando eliminará la carpeta node_modules y luego la volverá a cargar. Esta es una de las tareas más largas, por lo tanto, vale la pena usarla extremadamente raramente. En algunos proyectos, node_modules puede ocupar hasta varios gigabytes en el disco duro y, por lo tanto, la reinstalación llevará tiempo.


 rmdir android/app/build /s /q 

Durante el desarrollo, se notó que la compilación a menudo fallida es una consecuencia del hecho de que el recopilador no puede crear (o eliminar) una carpeta del directorio de depuración. Esta acción resuelve el problema de que reaccionar no puede eliminar la carpeta por sí solo. Pero al mismo tiempo, generar archivos para esta carpeta desde cero nuevamente tomará más tiempo.


 react-native start-reset-cache 

Inicie el Metro Bundler. Esta pestaña debe permanecer abierta durante todo el proceso de depuración. Si se produce un error, el registro de errores puede aparecer aquí. Lo más probable es que, si se produce un error, este proceso finalizará y deberá reiniciarse nuevamente.


 react-native run-android 

Instale la aplicación en un dispositivo o emulador conectado. La mayoría de los errores de compilación ocurren aquí, y algunos de ellos son comprensibles, pero algunos son bastante irracionales y se "curan" reiniciando todo el proceso.


Imagine el proceso de compilación con una secuencia de comandos para un proyecto (que ya tiene reino, redux, react-navigation, unas diez bibliotecas más) después de conectar Firebase.


 react-native start react-native run-android >>    debug react-native run-android >> , metro bundler  react-native start react-native run-android >>    debug react-native run-android >>  !  metro bundler ,   JS-   react-native start >>   restart         -  

No hace falta decir que lleva mucho tiempo. Y este no es un proceso de una sola vez: para el momento descrito, este procedimiento fue requerido después de casi cada cambio en el código del programa. Con cada nueva biblioteca, el proyecto se vuelve cada vez menos estable, y este proceso puede cambiar, a menudo para peor. La depuración de una aplicación es una de las funciones más importantes para un desarrollador, y en este caso su velocidad disminuye bastante.


Hablando de depuración. El depurador React Native tiene problemas no solo con el inicio. La corrección de los errores encontrados como resultado de la prueba también es un proceso bastante doloroso. En react-native, el código JS se traduce en código Native, pero se ofusca durante la traducción. Entonces, si no desea ver errores como "excepción de puntero nulo en zzz.yyy ()", entonces necesita usar el depurador incorporado, no puede simplemente leer excepciones en logcat. En caso de error, el depurador muestra una "pantalla de muerte" roja con su descripción, más o menos empujando hacia el camino de la corrección. Pero hay problemas con esta parte.


Bueno, cuando el error se ve así:



Está realmente claro lo que está sucediendo aquí: en lugar del objeto de matriz esperado, this.state.noteArray.map no está definido, lo que causa el notorio TypeError. Puede solucionarlo yendo a app.js: 14 y verificando el valor en esta variable antes de usarlo.


Peor cuando el error se ve así:



Entonces



Más o menos:



Las imágenes fueron tomadas de Internet, pero las vimos en vivo. Y a pesar de que se muestran en tiempo de ejecución, este error no se debe al hecho de que algo se hizo incorrectamente en su código. Esto puede deberse al hecho de que instaló la biblioteca incorrectamente, o si sus importaciones tienen dependencias incompatibles, o algo salió mal en el código nativo, y React intenta detectar el error. Cada error es individual y se resuelve de manera muy diferente. Es bueno que haya StackOverflow y al menos algún tipo de modo de depuración.


Peor aún, cuando un error no se reproduce en la depuración. Encontramos esta situación cuando intentamos construir una aplicación con una nueva versión de React con soporte para x64-architecture para Android. Al instalar una aplicación con un depurador, todo funciona bien. Pero tan pronto como creamos el probador en el teléfono, todo deja de funcionar y se rompe tan pronto como se trata de interactuar con la base de datos. Para depurar la no depuración de forma apresurada, utilizamos mensajes de consola, que en este caso fueron el componente reaccionar de ToastAndroid. Este componente muestra un texto breve al llegar a una determinada línea de código. Metódicamente, preferiblemente dividiendo el código por la mitad, localizamos la función en la que ocurre el error y descubrimos que el método Object.assign ({}, item) no funciona en la nueva versión de React. Fue una suerte que pudieras reemplazar esta función con un {... elemento} más corto mientras mantienes la funcionalidad de la aplicación, pero la búsqueda de este error costó aproximadamente una docena de horas de trabajo.


Luego se realizó un pequeño estudio en busca de razones. Al final resultó que, React Native utiliza diferentes motores de Javascript para interpretar el código JS en las versiones de depuración y producción: para depurar el motor Chrome JS y en JavaScriptCore. Sí, React Native no traduce JavaScript en código nativo, sino que interpreta mientras se ejecuta. Al mismo tiempo, el motor de depuración funciona mucho más estable y, por lo tanto, los errores se infiltran cada vez más en la producción. Por ejemplo, este artículo muestra cómo funciona el formato de fecha en diferentes condiciones. Volviendo al error: resultó que después de actualizar la versión React Native, el motor web de producción de producción perdió soporte para Object.assign (). Pero el motor de depuración seguía siendo el mismo.


Quizás la peor opción es el caso cuando la aplicación se rompe en lugares aleatorios, solo en la versión de producción y sin ningún registro de React Native. Ejemplo: después de instalar la versión de lanzamiento de la aplicación en el teléfono, "funciona por un tiempo" y luego "se apaga sin un error o advertencia en un momento aleatorio". Además, el error no se reproduce en todos los dispositivos. Al final, por prueba y error (y al detectar que el mencionado Firebase Crashlytics no envía los errores correspondientes), logramos capturar los registros de caída que se veían así:



Este texto ni siquiera se aplica a nuestra aplicación, ni siquiera estaba marcado en rojo. Pero después de que lo obtuvimos y fuimos a los foros, descubrimos que la nueva versión de React Native está rota. Y el anterior estaba roto. En el Rastreador de problemas oficial, el error "Android se bloquea: señal 11 (SIGSEGV)" existió durante dos meses, y para nuestra suerte dos días antes de ir allí (!) Se propuso una solución experimental que solucionó el error.


Es irónico que algunos desarrolladores que tuvieron que lidiar con Android Studio no sabían que el IDE tiene opciones como compilar / limpiar proyecto o archivar / invalidar cachés. Esto es necesario para deshacerse del comportamiento anormal de gradle, de mensajes de error falsos y advertencias, de errores de sincronización. Los desarrolladores preguntaron: "¿por qué deberíamos hacer el trabajo para nuestro IDE? En tales situaciones, estos comandos deberían ejecutarse automáticamente". Y pueden entenderse, pero al mismo tiempo, los IDE modernos hacen todo el trabajo difícil detrás de escena. Y estos desarrolladores simplemente no trabajaron con React Native.


Todos los anteriores son casos aislados que han ocurrido en las últimas semanas. Aquí no describimos la complejidad de ejecutar aplicaciones con Expo, al configurar el estilo de código en babel / eslint, no regañamos a JavaScript por una flexibilidad excesiva, no decimos cómo la depuración debido a la vinculación redux / reino se perdió casi por completo en uno de los proyectos. Teniendo en cuenta las dificultades descritas de soporte y desarrollo y el hecho de que para dos sistemas todo se multiplica por dos, ¿vale la pena considerar si React Native es realmente rentable? Después de completar nuestro tercer proyecto en este idioma, decidimos que no. Que piensas

Source: https://habr.com/ru/post/468901/


All Articles