Cómo funcionan las animaciones en React Native

React Native es un gran marco que le permite crear aplicaciones móviles multiplataforma. Es especialmente útil si es un desarrollador web y desea una solución rápida y de bajo costo para desarrollar aplicaciones móviles nativas que funcionen tanto en Android como en iOS. Bonificación: no tiene que gastar $$$ en equipos separados de iOS, Android y web.

Esto no solo reduce sus costos, sino que también le permite compartir una parte de su código base entre las tres compilaciones (Android, iOS y Web), lo que facilita la realización de cambios y la implementación de actualizaciones.

React Native también le permite trabajar bastante cerca del sistema operativo real, lo cual es importante para tareas críticas de rendimiento como las animaciones.

Las animaciones son una parte integral de cualquier aplicación porque la hacen interactiva y más atractiva para el usuario final. Pero muchas veces, mientras trabaja con animaciones, puede sentir que está trabajando con una caja negra.

Entonces, aprendamos cómo funcionan las animaciones en React Native. Puede comenzar a aprender animaciones en React Native desde cero desde esta lista de reproducción gratuita de YouTube.

La API animada

React Native expone una API llamada Animated. Consiste en muchas cosas maravillosas como valores animables, animaciones de primavera / tiempo y eventos. Pero no estamos aquí para discutir la API, lo dejo para los documentos oficiales y mi lista de reproducción de YouTube. Hacen un trabajo mucho mejor cubriéndolo por ti.

Lo que queremos discutir aquí es, de hecho, cómo React Native anima cosas en la pantalla y qué sucede debajo del capó.

Dos formas de animar

Debería saber cómo funciona React Native bajo el capó de mi otro artículo. (Dale una lectura rápida si aún no lo has hecho). Dado que React Native hace uso de React y JavaScript, existen precisamente 2 formas en que se pueden realizar animaciones en la pantalla.

En primer lugar, aclaremos un hecho. React Native construye vistas nativas reales en la pantalla, y no las representadas a través de navegadores web integrados como Ionic. Debido a esto, si desea animar una vista de alguna manera, en última instancia, debe hacerlo en la vista nativa.

JavaScript tiene que comunicarse con el sistema operativo de alguna manera para que la vista deba actualizarse. JavaScript se ejecuta en un hilo diferente al hilo de la interfaz de usuario (hilo principal), y solo este hilo de la interfaz de usuario puede actualizar las vistas. Entonces JS necesita usar el puente que React Native proporciona para serializar y comunicar esos datos al sistema operativo.

Trabaje en JS y actualice la vista nativa

Este enfoque significa que toma una vista que ya está visible en la pantalla del usuario y trabaja en lo que debe hacerse para su próxima posición en el hilo de JavaScript. Los pasos aproximadamente se ven así:

  1. La animación comienza
  2. JavaScript ejecuta la requestAnimationFramefunción, una función que intenta ejecutarse a 60 llamadas / segundo (60 FPS)
  3. JavaScript calcula la siguiente posición / opacidad / transformación / lo que sea que esté animando en la vista.
  4. JavaScript serializa este valor y lo envía a través del puente.
  5. En el otro extremo del puente, Java (Android) u Objective C (iOS) deserializa este valor y aplica las transformaciones dadas en la vista mencionada.
  6. El marco se actualiza en la pantalla.

¿Viste lo que pasó allí? Ninguno de los pasos realmente vuelve a renderizar un componente React Native. Esto significa que la API animada en realidad "pasa por alto" la filosofía de React de no alterar las variables de "estado".

La buena noticia: esto es realmente útil en el caso de las animaciones porque será demasiado lento y malo para el rendimiento si dejamos que React vuelva a renderizar un componente 60 veces por segundo.

Todo esto está muy bien, pero aquí hay un problema fundamental. JavaScript es de un solo hilo. Entonces, la naturaleza asincrónica de JavaScript no funciona aquí porque las animaciones son una tarea vinculada a la CPU. Echemos un vistazo a los pros y contras de este enfoque.

Pros

  1. Puede tener animaciones muy sofisticadas escritas en JS y visibles como animaciones nativas.
  2. Más control sobre el estado de la animación

Contras

  1. Gran penalización de rendimiento si su hilo de JavaScript está muy ocupado.
  2. Si el puente está ocupado, hay una disminución del rendimiento cuando los OS / JS quieren comunicarse entre sí.

Esa estafa es una gran estafa para ser honesto. Hay un video más abajo en el artículo que muestra este problema en tiempo real. Verá cómo JS lo arruina a lo grande con las animaciones cuando el hilo de JavaScript está ocupado.

¿Por qué se retrasan las animaciones JS?

Las animaciones realizadas en JS comenzarán a retrasarse cuando la animación esté en marcha y el usuario (o aplicación) solicite alguna otra acción que debe ser manejada por el hilo de JS.

Por ejemplo, imagina que se está produciendo una animación. Esto significa que JS está ocupado ejecutando la requestAnimationFramefunción. Suponiendo que las actualizaciones en sí mismas no son demasiado pesadas, suponga que un usuario comienza a tocar un botón en la pantalla que incrementa un contador.

Ahora, con la requestAnimationFramellamada frecuente, su árbol virtual de React también se vuelve a renderizar una y otra vez para tener en cuenta el aumento del contador.

Ambas son tareas vinculadas a la CPU que se ejecutan en un solo hilo, por lo que habrá un impacto en el rendimiento. requestAnimationFramecomenzará a eliminar marcos debido al trabajo adicional que realiza el hilo JS.

Todo esto significa que obtendrás una animación muy entrecortada.

Animaciones de controladores nativos

¡No se preocupe, porque React Native también le permite ejecutar animaciones en el controlador nativo! ¿Qué quiero decir con eso?

Bueno, en pocas palabras, significa que React Native descarga el trabajo de animación del hilo de JS al hilo de la interfaz de usuario (el sistema operativo) y le permite manejar la animación del objeto. Esto tiene un par de beneficios:

  1. El hilo JS (y el puente React Native) ahora es gratis para manejar otras tareas intensivas como toques repetitivos del usuario.
  2. Las animaciones son mucho más fluidas porque no hay serialización / deserialización ni sobrecarga de comunicación de puente.

¿Cómo logra React Native eso? La gente de React Native le permite, como desarrollador, proporcionar una propiedad llamada useNativeDrivercomo valor booleano cuando está construyendo un objeto de animación.

Cuando se establece en verdadero, React Native, antes de comenzar la animación, serializa todo el estado de la animación y lo que se debe hacer en el futuro. Luego lo transfiere una vez a través del puente al sistema operativo.

A partir de ese momento, el código Java (Android) o Objective C (iOS) ejecuta las animaciones en lugar de JavaScript para calcular el siguiente cuadro de animación y enviar esos datos una y otra vez a través del puente.

Esto acelera mucho las animaciones y las animaciones se ejecutan con mayor fluidez, especialmente en dispositivos de gama baja. Veamos una demostración en video de animaciones nativas frente a animaciones basadas en JS en React Native:

En este caso, los pasos se parecen a esto:

  1. La animación comienza
  2. JS serializa la información de la animación y la envía por el puente.
  3. En el otro extremo, OS recibe esa información y ejecuta la animación de forma nativa.

¡Eso es! Las animaciones son mucho más ligeras para el hilo JS ahora. No más requestAnimationFramecorrer sin fin.

Sin embargo, este método tiene sus pros y sus contras.

Pros:

  1. Animaciones más rápidas
  2. Hilo JS sin bloqueo
  3. Puente menos hinchado

Contras:

  1. Menos control sobre las animaciones (JS no puede ver lo que sucede en la pantalla una vez que comienza la animación "automática")
  2. Menos propiedades que manipular: el controlador nativo no admite todas las propiedades que se van a animar. Por ejemplo,   widtho heightno son animables de forma nativa, pero opacityy lo transformson.

En muchos casos, encontrará que puede trabajar con un conjunto diferente de animaciones usando el useNativeDriver: truepara crear un efecto similar que no se puede lograr sin configurar useNativeDriver: false.

El equipo de React Native está trabajando para agregar soporte para más propiedades mientras hablamos, pero por ahora, creo que funciona bien en este momento.

Conclusión

Este artículo le mostró cómo funcionan realmente las animaciones de React Native bajo el capó y por qué son hermosas.

¿Qué opinas sobre este artículo? ¡Dime conectándome conmigo en mis cuentas de Instagram y Twitter! ¿Nuevo en React Native? Empiece a aprenderlo en codedamn, ¡una plataforma para que los desarrolladores aprendan y se conecten!

¡Paz!