Uso de React para construir interfaces de usuario de juegos eficientes en Minecraft

Rate this content
Bookmark

Esta charla hablará brevemente sobre la historia de cómo Mojang Studios decidió usar los estándares web y React para construir la nueva pila de UI para Minecraft (Edición Bedrock), los desafíos que enfrentamos en torno al rendimiento y cómo llegamos a una solución que nos permitió seguir escribiendo UI declarativas, pero sin el DOM virtual.

Paulo Ragonha
Paulo Ragonha
25 min
25 Oct, 2021

Comments

Sign in or register to post your comment.

Video Summary and Transcription

Esta charla introduce el uso de React y las tecnologías web para construir interfaces de usuario en Minecraft. Discute los desafíos de incorporar nuevos desarrolladores a la tecnología actual y los beneficios de usar estándares abiertos. El orador explica el uso de Gameface, una solución para construir interfaces de usuario de juegos con React y Webpack. La charla también cubre la gestión del estado en un entorno de juego y el uso de facetas para la optimización del rendimiento. Concluye con una visión general de la marca Oryui y la disponibilidad de recursos en GitHub.

Available in English

1. Introducción al uso de React en Minecraft

Short description:

Bienvenidos a Usar React para construir interfaces de usuario de juegos eficientes en Minecraft. Soy Paolo, líder técnico en Mojang Studios. Nuestro objetivo es cambiar cómo se construyen las interfaces de usuario en Minecraft introduciendo un sistema de diseño. Ya hemos implementado la pantalla de logros basada en estándares web y React. Soportamos múltiples plataformas y tipos de entrada, incluyendo VR.

Bienvenidos a Usar React para construir interfaces de usuario de juegos eficientes en Minecraft. Mi nombre es Paolo. Soy el líder técnico en Mojang Studios aquí en Estocolmo. Y trabajo en un juego con el que probablemente estén familiarizados, que es Minecraft.

Soy parte de este fantástico equipo compuesto por artistas, diseñadores, desarrolladores de C++, desarrolladores de JavaScript, y un productor. Y nuestro principal objetivo es cambiar cómo se construyen las interfaces de usuario en Minecraft. Y estamos haciendo eso no solo cambiando la pila de tecnología, sino también introduciendo un sistema de diseño en el producto.

Estos son algunos de los componentes que tenemos, y es posible que los vean implementados en los próximos años. Y sí, en realidad ya estamos incluso en producción. Implementamos una pantalla el año pasado, que es la pantalla de logros. Así que si juegan Minecraft Bedrock Edition en su Xbox o PlayStation, probablemente ya hayan visto la pantalla. Y esta pantalla está completamente basada en estándares web, y está construida usando React. Y estas son todas las plataformas que soportamos, lo cual es también uno de los principales desafíos para nuestro proyecto. Así que necesitamos funcionar en Xbox One, en PlayStation, en Switch. Tenemos Android, teléfonos y tablets, iOS, teléfonos y tablets, Windows 10, Mac OS, casi todas las plataformas que existen, Minecraft funciona en ellas. Y luego necesitamos soportarlo. Y eso no es solo acerca de las capacidades del dispositivo, sino también de diferentes tipos de entrada. Así que necesitamos soportar touch, gamepad, todo tipo de cosas. VR, incluso, es soportado por Minecraft.

2. Uso de tecnologías web para las interfaces de usuario de Minecraft

Short description:

¿Por qué estamos utilizando tecnologías web para construir interfaces de usuario para Minecraft? Minecraft es un juego con motor personalizado, y la interfaz de usuario está completamente construida internamente. La incorporación de nuevos desarrolladores a la tecnología actual lleva mucho tiempo, por lo que queríamos una solución basada en estándares abiertos para una mejor mantenibilidad y una velocidad de iteración mejorada.

Pero, ¿por qué estamos utilizando tecnologías web, o debería decir estándares web, para construir interfaces de usuario para Minecraft? Hay muchas razones. Y algunas de ellas las cubrí en esta charla previa que di en 2018. Así que si tienes curiosidad, también puedes echarle un vistazo. Pero si no quieres mirar eso, aquí está el resumen. Básicamente, Minecraft es un juego con motor completamente personalizado. Así que no utiliza algo como Unreal o Unity. Así que la UI está completamente construida internamente, es completamente personalizada. Y actualmente eso ha sido un problema para nosotros cuando incorporamos a nuevos desarrolladores, les lleva mucho tiempo acostumbrarse a la tecnología y descubrir cómo usarla. Y queríamos pasar a una solución que nos llevara a una mejor mantenibilidad y que facilitara la incorporación de personas y también mejorara la velocidad de iteración. En resumen, queríamos hacer algo que estuviera basado en estándares abiertos, W3C, y queríamos obtener el beneficio de todas las grandes herramientas que el ecosistema JavaScript tiene.

3. Uso de Gameface para las interfaces de usuario de Minecraft

Short description:

No estamos simplemente tomando Chromium e integrándolo en Minecraft. En cambio, estamos utilizando una solución llamada Gameface de Korean Labs. Gameface es un subconjunto de estándares web abiertos, construido para interfaces de usuario de juegos con un enfoque en el rendimiento. Es como un pequeño navegador que ejecuta interfaces de usuario construidas con React y Webpack. Los desarrolladores web que se unen a Mojang pueden ser productivos desde el primer día y contribuir a la interfaz de usuario del juego.

Pero, ¿cómo estamos haciendo esto? ¿Estamos simplemente tomando Chromium e integrándolo en Minecraft? Técnicamente eso podría ser una posibilidad, y hay algunos juegos que realmente hacen esto. Lo que estamos haciendo es algo diferente. Hay una empresa llamada Korean Labs, y han estado haciendo soluciones basadas en Chromium durante un tiempo, para las interfaces de usuario de los juegos. Pero ellos, desde hace un tiempo, construyeron otra solución a la que llaman Gameface, donde tomaron los standards abiertos de la web, y luego construyeron solo un subconjunto de ellos en algo que llaman Gameface. Así que Gameface, podría considerarse algo así como un pequeño navegador, diría yo. Si construyes una UI para Gameface, es muy probable que funcione en Chrome o Firefox, pero puede que no sea el caso si simplemente eliges una UI aleatoria que construiste en Firefox y la pones en Gameface, puede que no funcione. Por ejemplo, tiene soporte para Flexbox, pero no tiene soporte para Floats. Y está construido con el objetivo principal de dirigirse a las interfaces de usuario de los juegos, por lo que performance es lo principal, es uno de los principales objetivos. Pero, aparte de sacar a Gameface de la ecuación, es una pila bastante estándar. Usamos React, usamos Webpack, hacemos unit tests con Jest. Así que si eres un desarrollador web que trabaja en una masterclass hoy y te unes a Mojang, probablemente serás productivo desde el primer día y podrás contribuir con una UI para el juego, lo cual es bastante impresionante y es una experiencia muy diferente a la que tenemos hoy en el estudio.

4. Gestión de Estado y Facetas en el Entorno del Juego

Short description:

Antes de discutir el rendimiento, entendamos cómo funciona la gestión de estado en un entorno de juego. En las aplicaciones web tradicionales, el estado se copia en el navegador, pero en un mundo de juego, el motor de juego C++ contiene el estado. Minecraft sirve como un buen ejemplo. El HUD muestra la salud, la saciedad y los elementos seleccionados, que pueden cambiar en función de la interacción del jugador. Nos referimos a estas porciones de datos como facetas. Las facetas son similares a los observables y proporcionan actualizaciones a medida que cambian los valores. El estado debe vivir en el lado C++, creando un almacén global. Nos inspiramos en Recoil y Jotai para construir nuestra solución, RackFacet, con algunas diferencias. RackFacet es una colección de paquetes que incluye RackFacet Remote para la comunicación entre JavaScript y C++.

Pero antes de hablar sobre performance, que es el tema principal que queremos discutir en esta presentación, primero necesitamos hablar sobre cómo funciona la state management y cómo es diferente cuando estamos en un entorno de juego.

Entonces, cuando miramos una aplicación web tradicional, podemos pensar en ella de esta manera. Tenemos tu navegador, por ejemplo, aquí tengo Firefox ejecutando la UI y eso tiene su propio entorno de ejecución de JavaScript y luego tenemos, digamos, un servidor en internet ejecutando Node.js y luego tenemos solicitudes HTTP y respuestas que regresan. Así que es una especie de separación de solicitud-respuesta y luego tenemos una copia del estado en el navegador.

Cuando entras en un mundo de juego, lo que usualmente tenemos es solo un solo proceso, ¿verdad? Tenemos el motor de JavaScript todavía en funcionamiento, que tendrá nuestro código de React y nuestro código de UI en él, pero tenemos el motor de juego C++ justo allí y eso es lo que llamamos nuestro backend y eso es generalmente el titular del estado. Si quieres entender esto, es mejor mirar un ejemplo y un buen ejemplo es Minecraft.

Entonces, si miras esta pantalla, que es básicamente lo que ves si estás jugando el juego, esto es el HUD. Vemos básicamente la información sobre cuánta health tiene tu personaje, la saciedad porque Minecraft es un juego de supervivencia, así que si no comes, empiezas a pasar hambre y puedes morir. También vemos los elementos a los que tienes acceso en tu barra de acceso rápido, así que estos son elementos que puedes cambiar rápidamente usando el gamepad, y qué elemento tienes seleccionado. Así que aquí puedes ver que tenemos el primer elemento seleccionado, que es la espada, pero un jugador también puede, interactuando con el juego, cambiar el elemento seleccionado a la Carne Podrida y eso no solo afecta al juego en sí, sino que también necesita ser reflejado en la UI. Y el jugador también puede recibir daño, ¿verdad? Digamos que un mob viene y un creeper explota al lado del jugador, y entonces necesitamos restar algo de health y aquí la health ha bajado a ocho. Así que podemos ver aquí que tenemos algo así como dos categorías de data, dos grupos de data. Y a esos los llamamos facetas.

Así que facetas es un término que acuñamos internamente en el estudio porque necesitábamos algo que no existía dentro de la base de code. Así que no podíamos usar modelo, por ejemplo. Pero esto es más o menos lo que es. Es solo una porción de data. Pero así como eso, como las facetas conceptualmente, son muy similares a un observable donde disponible con el tiempo. Así que nos suscribimos a una faceta, como digamos las estadísticas del jugador, y luego seguimos recibiendo actualizaciones sobre nuevos valores a medida que cambian, a medida que el jugador juega el juego, ¿verdad? Así que en la parte de abajo podemos ver cómo a medida que avanza el tiempo y el jugador pierde health, tenemos un componente hipotético de health del jugador que se actualiza con cuánta health tiene el jugador. Conceptualmente entonces lo que queremos es que el estado no viva en el lado de JavaScript, sino que más bien debería vivir en el lado de C++, que es nuestro backend, pero está viviendo justo allí dentro del mismo proceso. Queremos algo así como un almacén global y ese almacén global es el lado C++ del juego. Y cuando pensamos en almacenes globales, y miramos el ecosistema de JavaScript, hay un par de soluciones disponibles. Algunas de las más populares en estos días son Recoil o Jotai y son muy parecidas a esta moda donde tienes un almacén global. Y tomamos un enfoque muy similar a estas soluciones, y nos inspiramos en la API de Recoil's para construir algo que se siente muy familiar para que cualquiera que venga al estudio entienda qué conceptos estamos tratando de implicar. Pero hay algunas diferencias, por supuesto, que vamos a repasar en Next. Así que RackFacet es en realidad un pack, una colección de paquetes. Tenemos muchos paquetes. La parte que se ocupa de la comunicación entre los bits de JavaScript y los bits de C++ la llamamos RackFacet Remote. Y esa es la primera parte de la que voy a hablar ahora. Y supongo que lo primero que necesitamos mirar es cómo definimos las facetas, ¿verdad, los bits de estado que tenemos que se comparten entre el lado C++ y el lado de JavaScript.

5. Uso de Facetas Remotas y Optimización del Rendimiento

Short description:

Definimos el contrato de la API, utilizamos selectores para seleccionar facetas y las convertimos en estados de React. Nuestra solución requiere un proveedor para implementar el pegamento de JavaScript a C++. Configuramos oyentes y emitimos eventos para acceder y notificar datos. Las suscripciones y las funciones de limpieza aseguran actualizaciones eficientes. React ya es rápido.

Y si miraste... Si has usado Recall.js, por ejemplo, en algún momento, esto podría parecerte un poco familiar. Lo único es que estamos usando TypeScript aquí. Así que lo primero con lo que empezamos es definiendo el contrato de la API, que es simplemente una interfaz para este tipo de data. Esto es algo de lo que normalmente hablamos con los desarrolladores de C++ en una línea. Así que decimos, por ejemplo, que queremos tener una health que tenga un número y queremos tener una plenitud que tenga un número. Luego tenemos un identificador único. Y así es como, desde el lado de JavaScript, podemos solicitar una pieza particular de data al lado de C++. Luego tenemos la definición en sí, que es muy similar a un átomo, en un lenguaje de Recall.js. Y luego también tenemos selectores, que nos permiten seleccionar la faceta completa y cortar solo una pieza de ella, algo así como una función de mapa. Y aquí estamos seleccionando, por ejemplo, solo el atributo health de toda la faceta de estadísticas del lugar.

Y cuando queremos consumirlo, también es muy familiar, tendríamos solo algunos ganchos extra y algunos nombres diferentes aquí. Pero básicamente necesitamos primero usar el gancho useRemoteFacet para suscribirnos a esta faceta remota, para realmente iniciar y empezar a escuchar los eventos. Luego lo convertimos en un estado de React, que es la health allí, va a ser la cadena real donde el número que contiene la health, y luego podemos simplemente renderizar el resultado como un componente normal de React. La principal diferencia entre nuestra solución y las soluciones existentes en el espacio de código abierto es la suscripción. Nuestras facetas, realmente no tienen ningún valor hasta que empezamos a suscribirnos a ellas. Y después de eso, actúan prácticamente como observables. Así que en nuestra solución, tenemos que tener un proveedor que envuelva la aplicación y este proveedor, tenemos la responsabilidad de implementar el pegamento desde el lado de JavaScript hasta el lado de C++. Así que en este caso aquí, tenemos un motor, que es como un objeto global al que tenemos acceso. Y es algo así como un emisor de eventos, donde necesito desde el lado de C++, desde el lado de JavaScript, necesito configurar un oyente, que en este caso está escuchando el evento facet-updated player stats. Digamos que quiero acceder a los data para las estadísticas del jugador. Y luego necesito emitir un evento para notificar al lado de C++ o al game engine que estoy interesado en esos data. Y finalmente, puedo devolver una función que puede hacer una limpieza. Así que lo que sucede en la práctica es que cuando un componente se suscribe a, digamos, el selector de health del jugador que mostramos en el ejemplo anterior, si es la primera vez que esta función se llamará, configuraremos la suscripción y empezaremos a escuchar esos data. Y una vez que ese componente se desmonta, se llama a la función de limpieza y dejamos de escuchar. Y le decimos al lado de C++ que deje de notificarnos las actualizaciones. Eso es bastante genial. Y funciona bastante bien para nosotros.

Así que el siguiente paso, que es la parte interesante para todos ustedes es, por supuesto, cómo manejamos el performance. ¿Dónde optimizas las cosas para una solución para que pueda funcionar bien en un mundo de desarrollo de juegos? Y lo primero que supongo que hay que dejar claro es que React por sí mismo ya es bastante rápido.

6. Optimizando la Reconciliación de React con Actualizaciones de Facetas

Short description:

Al construir aplicaciones web con React, a menudo intentamos evitar re-renderizados innecesarios y mejorar el rendimiento. En este caso, proponemos omitir la reconciliación de React actualizando directamente el DOM desde las actualizaciones de facetas. Demostramos este enfoque con un ejemplo de una barra de progreso. Para lograr esto, nos suscribimos a las facetas utilizando el gancho use remote facet y transformamos el valor de la faceta utilizando el gancho use facet map. Sin embargo, cuando pasamos el valor transformado al div, React puede no reconocer el tipo de datos.

Si estás construyendo aplicaciones web, generalmente es suficiente usar simplemente React tal como es. Y soluciones como Recoil o Jotite, ayudan a reducir y seguir actualizaciones para que solo partes específicas de tu árbol de React se actualicen. Y cuando nos encontramos con problemas de performance en React, generalmente la recomendación es que revisemos nuestros componentes y veamos si tenemos algún tipo de re-renderizado que estamos haciendo innecesariamente y veamos si podemos evitar eso a toda costa.

Entonces, cuando miramos este concepto, es como, quiero decir, ¿qué pasaría si en lugar de simplemente evitar renderizados innecesarios, pudiéramos evitar todos los re-renderizados en general? ¿O podríamos tener una situación en la que básicamente no activamos la reconciliación de React? Entonces, aquí está cómo está sucediendo como nuestro ejemplo anterior, ¿verdad? La faceta se actualiza a través de un evento desde el lado de C++ que activa, que convierte, que por supuesto actualiza algún estado internamente en React, lo que activa la reconciliación y luego React a través del DOM virtual, descubre, oh, necesito actualizar este nodo de texto y así es como ocurre una actualización. Entonces, lo que estamos proponiendo es que podríamos simplemente saltarnos el intermediario e ir directamente desde la actualización de la faceta a la actualización del DOM. Entonces, si volvemos al ejemplo que teníamos antes, lo que estamos proponiendo es en lugar de tomar la faceta, que es una agradable estructura de data que contiene un valor a lo largo del tiempo, en lugar de desempaquetarla y convertirla en un estado, un estado de React, ¿podemos simplemente tomar la faceta y pasarla directamente al renderizado de React y dejar que el renderizado de React descubra cómo desempaquetar el valor, desempaquetar el valor de la faceta? Y eso es exactamente lo que hicimos. Entonces, queremos pasar la faceta, y eso actualiza directamente un nodo de texto. Entonces, veamos cómo lo hemos hecho. Entonces, tomando el ejemplo de antes, simplemente lo amplié un poco y lo hice un poco más interesante. Así que aquí tengo ahora una barra de progreso un poco más compleja. Así que en realidad estoy renderizando algunos divs para hacerlo con un estilo agradable. Puedes ver en la parte superior cómo se verá visualmente. Y luego vemos el resultado codificado. Tenemos una variable codificada allí con el progreso establecido en dos. Así que es un componente de React muy simple, solo renderizando una barra de progreso. Entonces, si queremos tomar este ejemplo y hacerlo de manera que omita completamente la reconciliación, ¿cómo podríamos hacer eso? Entonces, creo que el primer paso, por supuesto, es suscribirse a las facetas en el primer paso. Así que cambiamos eso para hacer el uso de remote facet, para tomar el valor del selector, y agarrarlo para ser utilizado en un componente. Pero el progreso aquí no es realmente un número per se, es en realidad solo la faceta todavía, como es una estructura de data que contiene el valor dentro de ella. Así que estoy obteniendo un error de tipo aquí porque no puedo hacer una operación aritmética con una faceta. No es un número. Entonces necesitamos descubrir una forma ahora de decir, bien, tengo esta faceta y quiero hacerle alguna transformación y convertirla en algo más. Si esto fuera un recoil en un estado global, probablemente solo usaría un selector. Como esto está dentro de un componente de React, lo que necesitamos es alguna forma de hacer un selector que se defina dentro de un componente de React. Y lo apoyamos a través de un gancho personalizado que tenemos que se llama use facet map, y es muy similar a un selector conceptualmente. Toma una faceta de entrada, en realidad puede tomar varias, pero en este caso, estamos pasando solo una, que es el progreso al que nos suscribimos en la línea anterior. Luego tenemos una función de mapa que tomará el progreso, que es el número, que viene de la faceta, y lo transformará en la cadena que contiene la unidad de píxel. Y el resultado de eso es también otra faceta, que ahora está sosteniendo en la variable de ancho. Entonces, el siguiente paso, por supuesto, es tomar este ancho y pasarlo al div. Pero si hacemos eso, React no va a estar contento. Va a ser como, hey, no sé qué hacer con este tipo de data, ¿verdad? Estás tratando de darme algo que no es una cadena, no es un número.

7. Renderizado con FastDiv y Facetas

Short description:

Introdujimos un nuevo div llamado FastDiv y creamos una serie de componentes que aceptan facetas como props. Esto nos permite crear un componente que se suscribe a una faceta remota y la mapea a una faceta de ancho. Hemos creado un renderizador que admite facetas como valores para props e incluso puede hacer componentes personalizados que admiten nativamente las facetas.

No sé cómo renderizar esto. Entonces, el siguiente paso en esto es que necesitamos cambiar el renderizador de React en sí para admitir este tipo de data. Y eso es lo que hicimos, al introducir un nuevo div al que llamamos FastDiv. Y en realidad creamos una serie completa de componentes que coinciden, algo así como uno a uno. Así que tenemos un FastB, un FastSpan. En lugar de aceptar solo números regulares, cadenas para las props, también aceptan facetas como una prop. Y al final, lo que tenemos es básicamente esto, ¿verdad? Un componente que se está suscribiendo a una faceta remota, convirtiéndose en una variable de progreso que contiene una faceta de progreso. Luego estamos mapeando eso en una faceta de ancho que tiene el ancho. Y luego estoy tomando eso y lo paso al FastDiff que luego actualiza esa prop en el DOM. Básicamente hemos creado un renderizador que admite nativamente las facetas, o podrías decir un observable ligero, como valores para las props. También podríamos ir un paso más allá y hacer componentes personalizados que también admiten nativamente las facetas como valor.

8. Uso de Facetas para Mejorar el Rendimiento

Short description:

Veamos cómo el uso de facetas mejora el rendimiento. Al extraer el componente de la barra de progreso y pasar el progreso como una faceta, evitamos desencadenar re-renderizados innecesarios. La implementación detrás de escena utiliza un renderizado personalizado y está disponible en el paquete react-facet-dom-fiber. Las pruebas de rendimiento en Xbox One y Chrome muestran que la solución basada en facetas es significativamente más rápida, tomando solo el 32% del tiempo en comparación con la implementación de React basada en estado.

Veamos cómo se vería eso. Si volvemos atrás y echamos un vistazo a este ejemplo del jugador health, ¿qué pasaría si queremos hacer también la plenitud? Queremos renderizar también la barra de progreso de plenitud. ¿Podríamos hacer eso? Supongo que lo primero es que queremos extraer los componentes para que podamos reutilizarlos en ambos lugares. Queremos tomar esta parte aquí que maneja la barra de progreso y extraerla a un componente de barra de progreso. Pero queremos pasar el progreso allí como una faceta. No queremos pasar como un número. Porque si desempaquetamos eso en la salud del jugador para convertirlo en un estado regular de React volveríamos básicamente a desencadenar la conciliación, y derrotaríamos todos los beneficios que estábamos tratando de lograr.

Así que aquí los tenemos, básicamente la salud del jugador y la plenitud del jugador, dos componentes usando la barra de progreso, y ambos pasando un progreso, cada uno con su propia faceta que contiene sus propios data. Y la implementación de la barra de progreso se ve así. En lugar de tomar un progreso que es solo un número, está tomando en su lugar una faceta de un número. Y tenemos el tipo específicamente disponible para allí. Pero por lo demás, la implementación aquí en el cuerpo es exactamente la misma que teníamos antes. Así que esto es más o menos lo que está sucediendo al final. Tenemos en la parte superior nuestra faceta remota de estadísticas de jugador. Una vez que se notifica de una actualización desde el lado de C++, esos data luego se pasan hacia abajo al selector remoto de salud del jugador que luego elige solo la health de los data. Eso luego se pasa a su uso de faceta remota, que desencadena la suscripción. Luego pasa por el uso de mapeo de facetas que transforma eso. Y luego de la forma en que finalmente llega al div de facetas, y luego se actualiza el DOM. Y lo genial de todo esto es que todo esto está sucediendo detrás de escena. No estamos desencadenando ningún re-renderizado en absoluto. Y toda esta implementación está construida como un renderizado personalizado, como dije, y está disponible en este paquete, react-facet-dom-fiber.

Pero todo esto es fantástico y es bastante genial, pero ¿cuánto mejora realmente el performance? Así que comparando, y puse aquí dos plataformas diferentes solo para darle perspectiva. Así que estoy ejecutando estos escenarios tanto en una Xbox One como en Chrome. Así que esta Xbox One está ejecutando el juego de Minecraft, y también tenemos Chrome en mi MacBook. Este ejemplo que estoy mostrando aquí básicamente está tomando la implementación de la barra de progreso que hicimos antes y simplemente cambiando su valor en cada cuadro y viendo cuánto tiempo estoy tomando entre cada implementación. A la izquierda, tenemos una implementación basada en el estado de React y ha tomado como el 100% del tiempo. Y en la Xbox One, podemos ver que una solución basada en Facetas toma solo el 32% del tiempo para hacer el mismo trabajo. Cuando miramos en Chrome, la diferencia es un poco menor, pero también es mucho más rápido cuando miramos la implementación de Facetas. Otro escenario que es muy interesante de ver es que imagina si tienes como una gran lista y la estás ejecutando a través de un montón de componentes y la estás memorizando. Así que cada componente está memorizado.

9. Comparación de Rendimiento con Facetas

Short description:

Cuando comparamos la solución basada en Facetas en la Xbox con la implementación estándar de React, la diferencia es enorme, siendo la Xbox significativamente más rápida. Plataformas como Xbox, PlayStation y Switch, que no tienen JIT habilitado, pueden tener diferentes características de rendimiento. Cuanto más complejos se vuelven los árboles de React, mayor es la brecha de rendimiento. Más información y ejemplos están disponibles en nuestro repositorio de GitHub.

Cuando observamos la solución basada en Facetas en la Xbox, la diferencia se vuelve masiva, tomando solo el 12% del tiempo. Y en Chrome, también es alrededor del 30% del tiempo. Este ejemplo lo mencioné porque es bastante interesante ver si tenemos una lista grande pero todos los elementos se actualizan a la vez, aquí podemos ver que la Xbox es en realidad mucho más rápida cuando la comparamos con la implementación estándar de React. Cuando miré Chrome en mi MacBook, la diferencia no es tan grande. Y lo principal que vale la pena mencionar es que cuando estamos ejecutando V8 en nuestro Chrome, en nuestras Macs, tenemos compilación justo a tiempo. Pero desafortunadamente en algunas plataformas como la Xbox, PlayStation y Switch, no podemos tener JIT habilitado. Por lo tanto, las optimizaciones y las bibliotecas a las que estamos acostumbrados se comportarán y tendrán diferentes características de rendimiento cuando las ejecutamos. Entonces, y también otra cosa importante es que cuanto más complejos se vuelven los árboles de React, entonces la brecha será más amplia y en realidad la implementación será más rápida en relación con la implementación estándar de React. Tenemos más datos, por supuesto, disponibles en nuestro repositorio de GitHub. Todos los ejemplos que mencioné aquí, puedes ir allí y ver sus implementaciones reales para entender mejor exactamente lo que están haciendo. No tengo mucho tiempo para entrar en detalles aquí, pero tenemos todo eso disponible en el repositorio de GitHub.

10. Introducción a Facets y Oryui

Short description:

Las Facets proporcionan una API más amigable con React con hooks que aceptan y devuelven facets. El paquete react-facet-core incluye estos hooks, como useFacetState y useFacetCallback. Las Facets son un conjunto de bibliotecas, incluyendo el tipo de datos observable ligero y el paquete remoto para compartir el estado entre JavaScript y C++. También tenemos un renderizador personalizado dentro de DOM fiber. Empezar con las facets es fácil usando el paquete de componentes DOM, que implementa componentes rápidos como componentes regulares de React. Estamos abriendo el código fuente bajo la marca Oryui y contratando para emocionantes posiciones en Mojang. Visita nuestro repositorio de GitHub para más información.

Pero no solo eso, quiero decir, si miras las facets, tenemos tiendas globales, en realidad tenemos un montón de hooks más que se convierten en una API mucho más amigable con React. Así que para todos los hooks de React que están a la derecha aquí, como use state, useReduce, o useEffect, tenemos implementaciones equivalentes en el mundo de las facets, pero en lugar de, ya sabes, la diferencia es que en realidad pueden aceptar facets como entrada, y podrían devolver una facet como salida. Y todo esto está disponible en el paquete react-facet-core.

Solo para ir realmente rápido, aquí está cómo se ve eso, donde tengo este componente aquí, donde estoy usando useFacetState, que es muy similar a useState, pero en lugar de que el valor sea solo una cadena, sería, por ejemplo, una facet de una cadena. Luego también tengo, useFacetCallback aquí, que es muy similar a useCallback, pero en lugar de eso te permite pasar un valor allí, que es una facet en lugar de eso. Hay más hooks y documentación disponible también en nuestra página de GitHub.

Así que en resumen, una facet no es solo una biblioteca, sino un conjunto de bibliotecas. Tenemos el nuevo tipo de datos que introdujimos, al que llamamos facets, por supuesto, que es un observable ligero que vive dentro del núcleo de la facet de React, y puedes usar solo el núcleo de la facet de React para construir algo sin necesariamente usar el renderizador personalizado o algo así o el paquete remoto. Tenemos el paquete remoto, que es el mecanismo que desarrollamos para tener como esta tienda de estado global para compartir el estado entre el lado de JavaScript y el lado de C++, y tenemos nuestro renderizador personalizado que construimos dentro de la fibra DOM. Así que estos son todos los paquetes que tenemos, y puedes echar un vistazo a la documentación para descubrir lo que hacen. No tengo mucho tiempo en la charla para repasarlos.

Pero parece un poco desalentador, pero en realidad es bastante fácil empezar si solo quieres mojarte los pies con las facets. Tenemos un paquete llamado componentes DOM. Lo que te permite hacer es implementar estos componentes rápidos que hicimos, pero en lugar de ser como componentes de host en un renderizador personalizado de React, en realidad son solo componentes regulares de React. Así que puedes ver aquí cómo se usan en un DOM regular de React para renderizar este componente. Y todo esto está siendo de código abierto. Estamos abriendo el código fuente bajo la marca Oryui. Oryui es una especie de iniciativa que estamos haciendo en los estudios Mojang para intentar estandarizar el desarrollo de UI en la industria del juego. Así que lo que estamos haciendo es tratar de impulsar eso. Así que Oryui tendrá facets de React para empezar, pero impulsaremos otros paquetes que estamos desarrollando también. Así que este es el fantástico logo. Y este es nuestro repositorio de GitHub. Así que si quieres mirar más rápido la base de código, si quieres aprender más, ve a GitHub y echa un vistazo a Mojang slash Oryui. Y por supuesto tengo que mencionar que estamos contratando en Mojang. Es un proyecto bastante emocionante. Quiero decir, no es en todos los lugares donde puedes ir y usar tus habilidades web para contribuir a uno de los juegos más grandes del mundo. Es bastante emocionante poder trabajar aquí. Y si quieres hacerlo, tenemos puestos abiertos para líderes técnicos, desarrolladores web. No dudes en contactarme o ir directamente a jobsmojang.com. Así que sí, muchas gracias. Tuve que correr un poco a través de las diapositivas, pero sí, si tienes alguna pregunta, creo que vamos a tener una sesión de preguntas y respuestas pronto. Así que muchas gracias y no dudes en contactarme también si tienes alguna pregunta. Adiós.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

A Guide to React Rendering Behavior
React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
Top Content
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
Building Better Websites with Remix
React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Top Content
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
React Compiler - Understanding Idiomatic React (React Forget)
React Advanced Conference 2023React Advanced Conference 2023
33 min
React Compiler - Understanding Idiomatic React (React Forget)
Top Content
React provides a contract to developers- uphold certain rules, and React can efficiently and correctly update the UI. In this talk we'll explore these rules in depth, understanding the reasoning behind them and how they unlock new directions such as automatic memoization. 
Using useEffect Effectively
React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Top Content
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.
Routing in React 18 and Beyond
React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Top Content
Concurrent React and Server Components are changing the way we think about routing, rendering, and fetching in web applications. Next.js recently shared part of its vision to help developers adopt these new React features and take advantage of the benefits they unlock.In this talk, we’ll explore the past, present and future of routing in front-end applications and discuss how new features in React and Next.js can help us architect more performant and feature-rich applications.
(Easier) Interactive Data Visualization in React
React Advanced Conference 2021React Advanced Conference 2021
27 min
(Easier) Interactive Data Visualization in React
Top Content
If you’re building a dashboard, analytics platform, or any web app where you need to give your users insight into their data, you need beautiful, custom, interactive data visualizations in your React app. But building visualizations hand with a low-level library like D3 can be a huge headache, involving lots of wheel-reinventing. In this talk, we’ll see how data viz development can get so much easier thanks to tools like Plot, a high-level dataviz library for quick & easy charting, and Observable, a reactive dataviz prototyping environment, both from the creator of D3. Through live coding examples we’ll explore how React refs let us delegate DOM manipulation for our data visualizations, and how Observable’s embedding functionality lets us easily repurpose community-built visualizations for our own data & use cases. By the end of this talk we’ll know how to get a beautiful, customized, interactive data visualization into our apps with a fraction of the time & effort!

Workshops on related topic

React Performance Debugging Masterclass
React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Top Content
Featured WorkshopFree
Ivan Akulov
Ivan Akulov
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
Concurrent Rendering Adventures in React 18
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
Maurice de Beijer
Maurice de Beijer
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
React Hooks Tips Only the Pros Know
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
Maurice de Beijer
Maurice de Beijer
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React, TypeScript, and TDD
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
Paul Everitt
Paul Everitt
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
Web3 Workshop - Building Your First Dapp
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
Nader Dabit
Nader Dabit
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
Designing Effective Tests With React Testing Library
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Top Content
Featured Workshop
Josh Justice
Josh Justice
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn