Construyamos una Navegación Espacial para TV

Rate this content
Bookmark
Slides

En esta charla, te llevaré a través de mi viaje cuando me uní al equipo que apoya nuestra aplicación para Smart TVs y compartiré mi experiencia aprendiendo una de las funcionalidades más esenciales pero ignoradas que tenemos.

Sergio Avalos
Sergio Avalos
34 min
12 Dec, 2023

Video Summary and Transcription

La charla de hoy trata sobre la construcción de una biblioteca de navegación espacial para Smart TVs. El orador comparte su experiencia y desafíos en la construcción de aplicaciones para Smart TVs. Demuestran la funcionalidad de la navegación espacial utilizando React y React Router. La clase del motor de navegación se desarrolla para manejar eventos de control de TV y navegar a través de los elementos. Se implementa la navegación circular para facilitar la navegación a los usuarios en las aplicaciones de TV.

Available in English

1. Introducción a la Navegación Espacial

Short description:

Hoy vamos a hablar sobre la navegación espacial y cómo construir la nuestra. Compartiré lo que aprendí y cómo podemos crear nuestra propia biblioteca. Discutamos por qué necesitamos construir nuestra biblioteca y los desafíos de construir aplicaciones para Smart TVs. Aunque los navegadores web son sofisticados, la navegación espacial todavía está en progreso.

Bienvenidos a todos, muchas gracias por unirse a esta sesión. Hoy vamos a hablar sobre la navegación espacial. Pero en lugar de hablar, vamos a construir la nuestra. Mi nombre es Sergio Abalos. Soy esposo, padre y dueño de un pequeño perro salchicha. Y cuando no estoy corriendo detrás de ninguno de ellos, también trabajo como desarrollador front-end en Spotify, donde formo parte del equipo que está construyendo el cliente de Spotify que puede funcionar en tu Smart TV. Esa es la razón por la que, aunque esta es una conferencia de React, no estaremos hablando sobre móviles, no, no estaremos hablando sobre escritorio o portátiles y especialmente no estaremos hablando sobre tu ratón. En cambio, vamos a hablar sobre el control de la TV, ese pequeño dispositivo aburrido que estoy seguro que todos ustedes tienen en sus salas de estar. Así que en caso de que te lo estuvieras preguntando, la navegación especial se refiere, como dice la definición aquí, a una modalidad de entrada del usuario que permite la navegación sin ratón por la página. Básicamente lo que esto significa es como la acción que haces con las teclas direccionales, arriba, abajo, izquierda y derecha de tu control de TV es lo que haces, como seleccionar una aplicación y seleccionar cualquier elemento o simplemente ejecutar cualquier acción. Así que la razón por la que elegí este tema es porque, como la mayoría de ustedes en la audiencia, apuesto a que han estado trabajando en móviles o escritorios. Lo mismo me pasó a mí hasta que llegué a desarrollar una aplicación para Smart TVs y quería traer esos temas que sentí que eran únicos para, obviamente para mí, pero la mayoría de ustedes que han estado trabajando en otras plataformas y no necesité buscar muy lejos. Vi que Spotify desarrolla internamente una biblioteca para manejar este caso específico, así que decidí echarle un vistazo, por pura curiosidad y me fascinó, no porque el código fuera wow, no, el código estaba bien, pero sentí que era un problema muy interesante de resolver, así que de eso se trata esta charla, quiero compartir con ustedes lo que aprendí y cómo empecé a profundizar en el código y, como dije, en lugar de simplemente hablar de ello, vamos a construir la nuestra. Disculpen porque no tengo mucha experiencia, no voy a hacer ninguna codificación en vivo, pero les voy a mostrar paso a paso cómo pueden construir su propia biblioteca, pero antes de todo, creo que es muy importante preguntarnos por qué necesitamos construir nuestra biblioteca, ¿estamos utilizando el tiempo de manera eficiente porque si estamos hablando de construir una aplicación en una Smart TV, ¿no debería la navegación especial ser proporcionada por la plataforma de la TV? Y la respuesta es que sí, lo es si estamos construyendo una aplicación completamente nativa. Así que déjenme tratar de explicar en el mercado de las Smart TVs, hay tantas marcas que está realmente bastante segmentado y cada uno de estos jugadores tiene su propio sistema operativo. Así que para ellos, uno tiene que ser viejo y aplicaciones nativas para que puedas instalar usando su propia tienda de aplicaciones. Así que no puedes evitar esto, pero para hacer nuestra vida mucho más fácil, decidimos usar una aplicación híbrida donde solo la interfaz de usuario se hace usando una aplicación web. Eso nos dio una increíble interoperabilidad porque podemos usar el mismo código fuente, el mismo proyecto para funcionar en todas estas plataformas. Pero por supuesto, vino a un costo. Y en este caso, perdimos el soporte para algunas de las características que la plataforma proporciona como la navegación espacial. Después de esto, estaba pensando como, okay, okay, es 2023. Hoy en día, los navegadores web son un software muy sofisticado. ¿No es la navegación espacial ya soportada por los navegadores web? Aún no. Es un trabajo en progreso. Hay un borrador para proponer esta nueva API desde 2019. Pero de nuevo, este mercado es muy nuevo. Creo que las aplicaciones de Smart TV's empezaron a salir en 2017. Así que, se siente como ayer. Así que, es comprensible que los navegadores estén poniéndose al día. Porque apuesto a que no todos los jugadores ahí fuera están usando este modo híbrido como lo estamos haciendo nosotros.

2. Construyendo Aplicaciones y Limitaciones

Short description:

Existe un proyecto de código abierto para aplicaciones de Smart TV, pero no pudimos usarlo porque no teníamos su biblioteca. Recomiendo usarlo. Podemos comenzar a construir nuestra propia aplicación envolviendo notas de navegación, que son elementos con los que el usuario puede interactuar, y asignándoles identificadores. Sin embargo, este enfoque tiene limitaciones con las vistas dinámicas, es propenso a errores y dificulta la depuración.

Entonces pensé, está bien, está bien, pero no somos la única empresa que construye una aplicación de Smart TV. Debe haber un proyecto de código abierto. Así que busqué y sí, en realidad hay uno. Y medios noruegos, muchas gracias por contribuir a eso. Desafortunadamente no teníamos su biblioteca en el momento en que comenzamos a construir nuestras propias aplicaciones. Así que esa es la razón por la que no pudimos usar la suya. Pero recomiendo totalmente usar esa.

Entonces, habiendo respondido esa pregunta, no estamos perdiendo nuestro tiempo, comencemos. Si te pregunto de la nada, tu intuición, ¿qué construirías? Hago esta pregunta porque esto es lo primero que tenía en mente cuando supe que había una biblioteca para resolver la navegación espacial. E incluso leí que el mismo enfoque fue utilizado por otras empresas en su blog. Quiero decir, ellos mismos lo pusieron. Es algo similar a esto. Imagina que tienes, por ejemplo, en el cliente de Spotify, el menú lateral donde tienes los diferentes elementos de él. Si quitas todas las imágenes y estilos, entonces obtienes el esqueleto con los enlaces a inicio, búsqueda, tu biblioteca y así sucesivamente. Y bueno, si estás usando una aplicación web, será un enlace a cada una de estas vistas. Así que nuestra intención era como simplemente envolver todos esos elementos que llamamos notas de navegación. Es decir, esos elementos con los que el usuario puede interactuar con el control de la TV y simplemente poner un identificador para identificar cada uno de los otros y decirles a dónde deben ir si suben y bajan y así sucesivamente. Así que este es un enfoque muy ingenuo. Esto realmente hace el trabajo. No hay problema con eso. Pero por supuesto, hay algunas pequeñas advertencias. Y la primera es que es muy difícil trabajar con vistas dinámicas. Y hoy en día, casi todas las aplicaciones ofrecen algún tipo de personalización de recomendaciones. Así que si estás construyendo la interfaz de usuario, lo más probable es que no sepas lo que vas a obtener. Y lo siguiente es que es propenso a errores porque, como desarrollador, necesitas poner los identificadores únicos. Somos humanos. Cometemos errores. Eso es común. Y finalmente, es solo que hay mucha información que tiene que ver con la navegación, el algoritmo para la navegación espacial, pero no tiene nada que ver con el diseño o la vista. Así que simplemente

3. Construyendo la Biblioteca de Navegación

Short description:

Construimos un sitio de demostración para demostrar la funcionalidad de la navegación espacial. El sitio tiene botones que generan regalos o premios aleatorios y un enlace para volver atrás. Sin embargo, el sitio no escucha los eventos de control de la TV. Te guiamos a través del código, que utiliza React y React Router para el enrutamiento. Las heurísticas para construir la biblioteca de navegación implican elevar todos los nodos de navegación.

hace que la depuración sea mucho más difícil. Así que pensamos, podemos mejorar esto. Hagámoslo mejor. Bueno, para hacer esta demostración, construí el sitio de demostración donde estamos, básicamente funciona como cualquier otra aplicación de escritorio, pero vamos a añadir encima de ella la funcionalidad para la navegación espacial. Así que vamos al sitio. Se ve algo así. Puedes ver que solo hay 5 botones o 510 botones. Cada uno de ellos te lleva a la misma página, pero genera aleatoriamente un nuevo regalo o un nuevo premio, y luego también tiene un enlace para volver a la página anterior, y de nuevo, y genera algo aleatorio. Así que funciona con el ratón, obviamente, como puedes ver, pero no escucha el evento de control de la TV. Así que hagamos eso. Añadamos la funcionalidad para hacer esto. Pero primero, solo quiero guiar a través del código que está ejecutando estos sitios de demostración, para que tengas una idea muy clara de cómo funciona esto. Primero, como estamos en esta conferencia de React, estamos usando la aplicación React, y es el índice que normalmente obtienes después de ejecutar la aplicación Create React donde estamos renderizando nuestro componente de aplicación. El componente de la aplicación se ve así. Tiene una configuración de enrutador utilizando la biblioteca React Router, donde solo tenemos dos rutas diferentes. La primera es la página de bienvenida, la que ves tan pronto como cargas la aplicación, y la página de sorpresa, a la que te llevan después de hacer clic en una de las cajas de preguntas. Si vamos a esas dos vistas, es, de nuevo, algo muy similar. Tenemos nuestro componente React. Para el primer componente, la página de bienvenida, tenemos un array vacío de 10 ubicaciones donde lo usamos solo para renderizar el mismo componente una y otra vez 10 veces. No, ese es el componente de la caja de preguntas. Y por otro lado, la página de vista de sorpresa, tenemos codificado el camino de los diferentes premios, la imagen, perdón, de los diferentes premios. Elegimos uno al azar, y luego simplemente renderizamos esa imagen, junto con un enlace para volver a la página anterior. Finalmente, lo que llamamos el elemento de enlace, es, de nuevo, algo muy simple. Tenemos un componente React para renderizar la caja de preguntas, que simplemente está utilizando un enlace de la biblioteca React Router que simplemente está envolviendo una caja de preguntas que básicamente estás renderizando. Por otro lado, es exactamente lo mismo, en lugar de... La única diferencia es que en lugar de renderizar la caja de preguntas, obviamente estamos renderizando los hijos, que es solo un componente de texto. Genial. Entonces, ¿cuáles son las heurísticas para renderizar esto... Perdón, no para renderizar, para construir la biblioteca de navegación. Puedes hacerlo de muchas maneras, pero el método que decidimos hacer es este. Primero, elevamos todos los nodos de navegación, es decir, todos los nodos con los que el usuario puede interactuar con el control de la TV en la aplicación.

4. Construcción del Motor de Navegación

Short description:

Escuchamos los controles de la TV y encontramos el nodo seleccionado en base a la selección actual y la tecla presionada. La clase del motor de navegación tiene métodos para registrar nodos y manejar eventos de navegación. Creamos un esquema y una clase para los nodos de navegación, y proporcionamos un proveedor de contexto para la instancia. La API externa utiliza una función de gancho que devuelve el elemento renderizado y un booleano para el enfoque. Desarrollamos la función de gancho useFocusRef para manejar referencias de elementos y registrar/desregistrar nodos. Probamos la funcionalidad y confirmamos la presencia de un nodo.

Luego escuchamos los controles de la TV que vienen... Lo siento, a los eventos que vienen del control de la TV. Luego encontramos el nodo seleccionado dependiendo de dónde está la selección actual y dónde quieres ir, dependiendo de la tecla que estaba presionando. Y finalmente, solo actualizamos el estado para indicar cuál es el elemento que debería ser seleccionado ahora.

Si miras el diagrama desde el paso uno al tres, esta es la forma en que decidimos construir. Tendremos una clase de motor de navegación que tiene dos métodos. Uno para registrar todos esos nodos de navegación, y otro que manejará la navegación que estará escuchando las teclas eventos de bajada que vienen del control de la TV. Genial. Así que empecemos con el primer paso, los nodos de navegación. Aquí tenemos un esquema para el nodo de navegación que solo tendrá un identificador y una referencia al elemento HTML que se renderiza. Luego creamos la clase que tendrá una variable privada, un array de estos nodos de navegación y métodos para añadir valores, y otro método para eliminar los valores. Y luego vamos al script de índice donde creamos una instancia de esta clase NavigationEngine. Luego, solo para fines de depuración, lo añadimos a el ámbito global. Verás cómo lo usamos en cada uno de los pasos cuando estamos testing. Y finalmente, proporcionamos un proveedor de contexto de esta instancia, para que esté disponible a través de toda la aplicación usando un proveedor de contexto. Genial. Luego volvemos a la caja de preguntas y el enlace de navegación donde esta va a ser la API externa que usamos. Y es algo muy simple comparado con lo que estábamos usando antes cuando mencioné el enfoque ingenuo. Tenemos una función de gancho que devuelve solo dos valores. El primero es una devolución de llamada para saber qué elemento estamos renderizando, como qué elemento HTML. Y el segundo es solo un valor booleano que te dice si ese elemento que estás renderizando está enfocado o no. Eso es tan simple como eso. Genial. Así que, desarrollamos esta función de gancho llamada useFocusRef que, como mencioné, tiene una función de devolución de llamada donde tenemos un valor de referencia y también creamos el valor de devolución de llamada que será ejecutado por el elemento HTML solo para apuntar una referencia a este elemento. Luego creamos un identificador único. Obtenemos una navegación, lo siento, una instancia del motor de navegación y, con la ayuda de la función de gancho useEffect, cada vez que este componente se renderiza llamamos al método registerNode y cuando se desmonta llamamos al método unregisterNode solo para asegurarnos de que no hay fugas de memoria. Por ahora, vamos a dejar el valor isFocused como falso, pero en el último paso vamos a volver y poner el valor real, pero no te preocupes por eso ahora. Genial, así que volvemos a nuestra aplicación y luego vamos a hacer rápidamente una prueba. Si consigno el motor de navegación podemos ver que efectivamente tenemos diez elementos, y puedes ver que estoy apuntando a la referencia del primer elemento HTML, y así sucesivamente. Si hago clic en cualquiera de ellos, entonces

5. Escuchando el Evento de Control de TV

Short description:

Regresamos y ahora tenemos diez de nuevo. Por cierto, en caso de que te estés preguntando de dónde son estas capturas de pantalla, es solo un plan de respaldo en caso de que una aplicación de demostración no funcione, pero afortunadamente todo va bien. Podemos ir al paso número dos y escuchar el evento de control de la TV. Este es uno de los pasos más simples en los que solo estamos agregando un detector de eventos para el evento de tecla hacia abajo. Ya tenemos un array donde hemos identificado cuáles son esas teclas que representan estas direcciones, y luego también tenemos un mapa entre los valores internos que definimos como una de las teclas de dirección, y el otro que viene de la plataforma.

debería renovarse correctamente, y sí, puedes ver que solo tenemos un nodo. Volvemos atrás y ahora tenemos diez de nuevo. Genial, está funcionando. Por cierto, en caso de que te estés preguntando de dónde son estas capturas de pantalla, es solo un plan de respaldo en caso de que una aplicación de demostración no funcione, pero afortunadamente todo va bien. Pero puedes ignorar esto por ahora. Genial, entonces ahora podemos ir al paso número dos y escuchar el evento de control de la TV. Este es uno de los pasos más simples en los que solo estamos agregando un detector de eventos para el evento de tecla hacia abajo, y la función de devolución de llamada que vamos a pasar es la que creamos, o lo siento, obtenemos del manejador getKeyEvent que desarrollamos de esta manera. Básicamente esta función de devolución de llamada solo está utilizando un método o función para identificar si la tecla que se presiona es una de las cuatro teclas para la dirección, y solo nos importa eso en esta aplicación, y si sabes que hay algunos controles de TV que tienen muchas teclas. Así que por eso solo queremos centrarnos en estas cuatro. Y para hacer eso, ya tenemos un array donde hemos identificado cuáles son esas teclas que representan estas direcciones, y luego también tenemos un mapa entre los valores internos que definimos como una de las teclas de dirección, y el otro que viene de la plataforma. En realidad, si estás ejecutando esto solo para la plataforma de escritorio, realmente no necesitas este paso. Pero sentí que era importante mostrarlo aquí porque estos valores, estos mapas que tengo aquí son muy diferentes de plataforma a plataforma, porque cada plataforma tiene sus propios valores. Así que este es un ejemplo de una de esas tareas de integración que cada una de las aplicaciones de navegación tiene que hacer. Pero como dije, esto es completamente necesario para esto

6. Encontrando y Seleccionando los Próximos Nodos

Short description:

Probamos si estamos escuchando los eventos del teclado. Utilizamos el método getboundingclientrec para obtener las coordenadas y tamaños de los elementos de navegación registrados. Filtramos los elementos en función de la dirección de la tecla presionada, el eje principal del elemento seleccionado actualmente y la distancia desde el nodo seleccionado actual. Implementamos el método handleNavigation en el motor de navegación para manejar las direcciones de las teclas, los métodos de filtro y la selección del próximo nodo. Reemplazamos console.log con handleNavigation para las teclas de dirección de control de TV. Probamos la funcionalidad presionando hacia abajo y hacia la derecha.

aplicación de demostración. Genial. Podemos volver al número dos, y solo vamos a probar si estamos escuchando los eventos del teclado que puedes ver aquí. La flecha izquierda, la flecha... Permíteme hacerlo una vez más. Si presiono hacia abajo, puedes ver que es hacia abajo. Si presiono hacia arriba, y así sucesivamente, izquierda y derecha. Genial. Entonces podemos ir al paso número tres, el que creo que es el más divertido, encontrar la nota seleccionada. Entonces, en caso de que te estés preguntando, ¿por qué necesitamos la referencia al elemento HTML, es porque puedes llamar a este método llamado getbounding client rec que te da las coordenadas, lo que sea, de acuerdo con el viewport de donde se renderiza el elemento, y también la dimensión. Siento que esto es súper genial porque si tomas todos los elementos de navegación que has registrado hasta ahora, y ejecutas este método para cada uno de estos elementos, entonces obtienes toda la información que necesitas, las coordenadas y los tamaños. Así que puedes olvidarte de lo que estás renderizando con esta información. Tienes todo lo que necesitas para simplemente seleccionar, para crear el algoritmo y seleccionar el próximo nodo que debería ser seleccionado. Entonces, hagámoslo. ¿Cómo elegimos el próximo nodo? Primero filtramos por la dirección de la tecla que se presionó, luego filtramos por el eje principal del elemento seleccionado actualmente y finalmente, cuando te limitas a solo esos pocos, entonces solo eliges el que está más cerca de este nodo seleccionado actualmente. Veamos uno paso a paso. Imagina que tienes una matriz de 5 por 5, un poco más grande de lo que vimos antes en la aplicación de demostración, y estás sentado en el medio. Si vas a la derecha, entonces quieres las dos últimas columnas, pero si vas hacia arriba, entonces quieres las dos primeras filas. Luego eliges por el eje principal, por ejemplo si te estás moviendo horizontalmente, tu eje principal es el margen superior y el margen inferior, pero si te estás moviendo verticalmente, entonces eliges el margen izquierdo y el margen derecho. Después de eso, entonces simplemente eliges por la distancia, el que está más cerca. Ok, implementemos esto en el código. Primero vamos al motor de navegación y creamos un método llamado handleNavigation que tomará como parámetro la dirección de la tecla que se presionó. Luego, como mencioné antes, filtramos por la dirección de esa tecla, y para facilitarnos la vida, ya tenemos codificado el método de filtro que vamos a llamar dependiendo de la dirección. Hacemos un enfoque similar pero en este caso va a ser para el eje principal, luego elegimos por la distancia, y finalmente si hay algún elemento que esté seleccionado, entonces simplemente creamos una nueva variable privada llamada selectedNode para el motor de navegación. Finalmente reemplazamos el console.log que teníamos antes con este método llamado handleNavigation cada vez que se presiona una de las teclas direccionales en el control de TV. ¡Genial! Entonces podemos ir y probar, vamos al paso número 3. Primero vamos a, esto es molesto, déjame eliminar las advertencias, motor selectedNode, así que podemos ver que inicialmente está indefinido. Si presiono hacia abajo, entonces vamos a tener un nuevo valor. Y está hecho. Vamos a la derecha ahora.

7. Actualizando el Cursor y Probando la Funcionalidad

Short description:

Bajamos, boom, y luego vamos a la izquierda. Está funcionando. Mira, incluso puedo hacer esto, y puede ir. Vamos al último paso, actualizar el cursor. Añadimos un método de suscripción y publicación para informar qué nodo está seleccionado. Añadimos métodos para añadir suscripciones y ejecutar devoluciones de llamada. Reemplazamos el valor falso en use focus ref con use node focus hook para manejar el estado de enfoque. Probamos la funcionalidad y funciona.

Boom, está ahí. ¿Lo ves? Bajamos, boom, y luego vamos a la izquierda. Ok, excelente, así que está funcionando. Mira, incluso puedo hacer esto, y puede ir. Genial, entonces vamos al último paso, actualizar el cursor. Si volvemos al diagrama que mostré antes, solo hay una nueva adición que podemos hacer. Es un método de suscripción y publicación donde el nodo que está registrado va a ser suscrito dentro del motor de navegación, y luego cada vez que hay un evento de manejo de navegación que notificamos a cada uno de ellos, solo para informar cuál está seleccionado y cuál no. Entonces volvemos al motor de navegación, añadimos un método para añadir suscripción, básicamente, para mantener las devoluciones de llamada que vamos a ejecutar cuando haya una navegación de manejo. También tenemos un método para luego ejecutar todas esas devoluciones de llamada y como dije cada vez que hay un nuevo elemento que ha sido seleccionado, simplemente llamamos a este notificar a todos los suscriptores. Por último, vamos al use focus ref donde tú recuerdas que teníamos el valor falso, ahora lo eliminamos y lo reemplazamos con un nueva función de gancho llamada use node focus que básicamente lo que va a hacer va a mantener un estado local para este componente donde por defecto va a ser falso pero con la ayuda de una función useEffect cada vez que este componente se monta lo primero es ir al motor de navegación y comprobar como hey se supone que debo estar enfocado y dependiendo del valor que actualizaste y si no entonces básicamente te suscribes para que cada vez que hay una navegación de manejo compruebas de nuevo como se supone que debo estar enfocado y luego simplemente lo actualizamos en consecuencia. Obviamente pasamos cuando este componente se desmonta obviamente queremos cancelar la suscripción de nuevo para evitar fugas de memoria y genial tenemos todos los requisitos básicos y podemos ir y probar rápidamente el paso número cuatro pausa para beber agua volvemos y podemos ver esto funcionando está bien, así que todavía funciona con el ratón ¿verdad? es

8. Implementando la Navegación Circular

Short description:

En las aplicaciones de TV, la navegación circular es una característica común que facilita el manejo de las opciones de control limitadas. En lugar de requerir que los usuarios naveguen de nuevo al principio cuando llegan al final, la navegación circular les permite continuar en la misma dirección. Para implementar la navegación circular, necesitamos crear un contenedor de navegación para marcar la región, construir un árbol de navegación y actualizar el algoritmo de selección de nodos. Comenzamos envolviendo la región deseada en un componente de contenedor de navegación y utilizando el gancho useRegisterNavigationalContainer. El contenedor de navegación tiene un nuevo atributo llamado 'ciclo' para especificar la dirección de navegación. Luego creamos un proveedor de contexto para definir el ID del ancestro para los elementos que se están renderizando dentro del contenedor.

importante comprobar eso y excelente, está funcionando. ¿Estás listo para un desafío? Esto es algo que sentí que era muy importante para demostrar aquí en esta charla. Si ves que hay un nuevo botón llamado nivel arriba y lo que tenemos es como si tuviéramos dos filas, donde una de ellas funciona como de costumbre, la llamo normal, pero luego hay otra donde la llamamos circular ¿a qué me refiero con circular? En las aplicaciones que se ejecutan en un TV hay una característica muy común llamada navegación circular. Seamos honestos, seamos francos. Usar el control de la TV no es lo más amigable para el usuario. Quiero decir, mucho más natural es con el ratón donde seleccionas como tu mano describe pero aquí solo tienes cuatro teclas. Así que no es muy amigable para el usuario y hay esta característica para hacerlo un poco más fácil de manejar. Así que en ciertos radios, por ejemplo el mismo menú, quieres suavizar las restricciones, es decir que si el usuario está haciendo clic abajo, abajo, abajo, y llegan a la parte superior, en lugar de pedirles que presionen arriba, arriba, arriba para ir al principio, simplemente pueden continuar haciendo clic abajo y luego simplemente retomas el curso. Por eso nos referimos a la navegación circular. Creo que esto es un cambio total de juego y, francamente esta es la característica que realmente me metió en esto, y explicaré por qué.

Imagina que estamos en la aplicación de demostración y tenemos esta nota donde quieres distinguir aquellos que pertenecen a la navegación circular y el resto que no. Si miras este ejemplo, entonces te das cuenta de que ya no podemos usar la lista que tenemos porque necesitas distinguir cuál pertenece a esta lista. Así que en lugar de una lista terminamos usando un árbol de navegación y esto es lo que creo que es fascinante porque ya no es solo sobre las coordenadas de la dimensión, también es sobre la relación entre uno y otro. Así que vamos a construir esto. Estos son los pasos que podemos hacer para la navegación circular y de nuevo podemos usar muchos pasos pero estos son los que decidimos proponer. Primero creamos un contenedor de navegación solo para marcar qué región pertenece a la navegación circular y cuál no. Luego construimos un árbol de navegación y finalmente actualizamos el algoritmo de selección de nodos. Comencemos con el primer paso. Así que recuerdas esta vista que te estoy mostrando. Este es el código Muy similar a esta página de bienvenida que mostré antes. En lugar de tener un array de 10 elementos vacíos usaremos 5. Lo usaremos solo para renderizar dos veces, pero para la segunda vamos a envolverlo en el contenedor de navegación solo para distinguir la región donde queremos aplicar este nuevo atributo. Luego creamos un nuevo componente React llamado el contenedor de navegación donde llamamos a esta función de gancho llamada useRegisterNavigationalContainer y esta función es muy similar a la que estábamos usando para registrar el nodo normal de navegación. La única diferencia es que primero no tenemos ninguna referencia al elemento HTML porque no estamos renderizando nada y segundo tenemos un nuevo atributo, el nuevo parámetro para los atributos de este contenedor de navegación. Así es como se ve, lo cual creo que es más claro si te muestro el esquema. Tenemos un nuevo tipo llamado contenedor de navegación que tiene un nuevo atributo, un nuevo atributo llamado atributo donde solo por ahora puede ser tendrá la propiedad ciclo que describe si el ciclo es vertical o horizontal y como estamos usando TypeScript no necesitamos actualizar el método en el motor de navegación para que pueda recibir ambos tipos. Bien, entonces vamos y comprobamos si el contenedor de navegación se renderiza correctamente. Si voy al motor de navegación y traigo el valor del nodo verás que tenemos los 10 elementos pero hay uno aquí que no tiene ningún elemento HTML comparado con este y este tiene la propiedad ciclo por lo que se está registrando correctamente. Si vuelvo entonces solo tenemos los 11 elementos como de costumbre el último elemento es solo el enlace para ir a esta página. genial vamos al paso número dos construir un árbol de navegación. Para construir la relación o como invertir en el árbol de navegación lo único que vamos a hacer es que vamos a añadir un parámetro llamado ID del ancestro que apunta a el padre. Francamente es un enfoque diferente al que elegimos internamente, depende, quiero decir, este es el enfoque que decidió usar la media noruega en Spotify decidimos en cambio mantener un array de los hijos. Creo que no hay mucha diferencia entre ellos pero decidí elegir este método porque es más fácil de demostrar que tener el array de hijos pero puedes ir con lo que sea. bien, ahora creamos un proveedor de contexto donde definimos cuál es el ID del ancestro de los elementos que vamos a estar renderizando déjame tratar de explicar. si vamos a la aplicación de índice lo siento en el índice script entonces tendremos el proveedor de contexto envolviendo toda la aplicación donde por defecto el ID del ancestro va a ser la raíz es que es por defecto pero en el contenedor de navegación vamos a actualizar el valor del ID del ancestro con el ID único que obtenemos cuando estábamos registrando en este contenedor de navegación por lo que significa que cualquier hijo que se renderice dentro de este contenedor de navegación tendrá como ID del ancestro este nuevo ID. así que ahora vamos y probamos si comprueban si el árbol de navegación se renderiza correctamente si miro las notas entonces puedes ver que por defecto todos los nodos de navegación tienen como padre lo siento el ancestro el ID de la raíz si voy al nivel superior entonces esto va a ser diferente porque algunos de ellos tienen la raíz pero estos restos tienen el nuevo contenedor de navegación que puedes ver que es el mismo de este termina con uab uab genial impresionante podemos ir al último paso del nodo algoritmo para este tenemos tres casos diferentes primero cuando estás navegando a otro nodo que está dentro de la misma rama por lo que es algo que ya hemos cubierto pero luego también tenemos cuando donde cuando el cursor es moviéndose fuera de esa rama y finalmente cuando viste a alguien fuera de la rama pero a un elemento faltante para el primer caso donde ya estamos haciendo eso por lo que simplemente elegimos el nodo más cercano pero en el segundo caso necesitamos comprobar si el nodo ancestral tiene este modo de ciclo y si ese es el caso y luego también comprobamos si coincide con la tecla direccional es decir que si estás en el vertical solo te importa el arriba y abajo y si estás en el horizontal y solo te importa el izquierdo y el derecho si ese es el caso entonces encontraremos el nodo de ciclo y si no entonces simplemente elegimos el nodo más cercano como lo hicimos antes muy similar con el tercer caso el único patrón común es que necesitamos encontrar el nodo de ciclo cómo lo hacemos volvamos a la anterior matriz que teníamos antes el fuego y 5 por 5 e imagina que estás sentado este que estás que el cursor está seleccionado ahora en el último nota correcta vamos a imaginar que tenemos que el cursor está todo el camino a la izquierda como si tuviéramos un margen izquierdo que estamos seleccionando y desde allí seleccionamos el más cercano que va a estar en el otro lado así que con eso en mente vamos a la vamos a implementarlo por código y vamos al motor de navegación y todo lo que escribimos antes en vivo para en el manejo navegación lo movemos a un nuevo método privado llamado find next target node so I quiero decir solo para tener el caso por defecto donde simplemente tomamos el nodo más cercano y luego comprobamos si el nodo donde sea que estemos navegando pertenece a la misma rama si no entonces comprobamos si quiero decir la navegación debería ser circular y si ese es el caso son muy similares a los que hicimos antes vamos a encontrar el elemento en esa dirección y vamos a usar los valores codificados pero estos valores son los que estamos imaginando como si estás bajando entonces podrías terminar estás seleccionando todo el top el top mi margen de la viewport y lo mismo si estás subiendo lo siento si estás subiendo lo seleccionas abajo si estás bajando entonces lo seleccionas lo siento solo para quedarme en mi cabeza un poco bien así es como encuentras la navegación circular no importa si importa si no debería ser circular entonces haces lo mismo que antes y oh lo siento y luego simplemente seleccionas el nodo objetivo me adelanté un poco lo siento por eso y ven donde puede venir y testing así que estamos en el caso normal puedes ver que no hay navegación circular ni aquí pero si vamos a esta página y vamos a la navegación circular está haciendo como debería mmm eso es bastante mucho para mí pero confía en mí esto es solo el principio porque solo se pone más complicado desde aquí quiero decir obviamente tu aplicación sabes que no va a parecerse a una matriz perfecta tendrá como columnas filas y así sucesivamente así que literalmente vas a estar lidiando con H casos ¿qué pasa con esos inconvenientes y molestos modelos más que te dicen como hey deberías comprar premium y yo creo que deberías entonces espera eso es un caso interesante porque la navegación y sabes que todavía lo tienes en el fondo quiero decir que todavía están allí pero ¿quieres centrar toda la atención del usuario solo en esos elementos que están dentro de la ventana del modelo? así que ese es otro caso que tienes que soportar en el contenedor de navegación y finalmente performance no hemos hablado de esto uno en absoluto y este es uno de los más cruciales porque si quieres ejecutar esto aplicación más solo tienes 10 milisegundos y 10 milisegundos por frame quiero decir que la biblioteca de navegación no puede tardar tanto así que tienes que hacerlo lo más pequeño posible para no crear mucho sobrecarga para el resto de la aplicación pero eso es para otra vez hecho de todos modos si te sientes curioso acerca de estos el código que te mostré o cualquier cosa que hayamos hecho y lo dejé aquí el enlace al Red Bull que puedes ir y comprobarlo y jugar y también escribí ese post en nuestro blog de ingeniería donde puedes encontrar en detalle todo lo que hemos hecho aquí sin embargo te sientes inspirado y si quieres empezar a crear tu propia aplicación de TV inteligente no tienes que hacer esto por scratch por scratch como dije la Media Noruega ha proporcionado esto utilidad para que puedas ir y usarla y finalmente si te sientes desafiado y tú sientes que lo compliqué demasiado ponte en contacto mi objetivo personal es solo crear una community donde podamos ayudarnos mutuamente así que si estás corriendo en el mismos casos y nosotros quiero decir ponte en contacto y podemos continuar una conversación podemos crear esta community y ayudarnos mutuamente pero eso es todo por ahora gracias muchas gracias espero oír de ti pronto

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