Cómo pasé de ser escéptico sobre Relay a enamorarme de él

Rate this content
Bookmark

La integración de GraphQL (y la obtención de datos de la API en general) se vuelve bastante repetitiva y compleja a medida que nuestra aplicación crece. Se deben construir nuevas características que son similares a las características que ya existían, pero no está claro qué partes se pueden reutilizar (por ejemplo, la paginación). Nuevos miembros se unen al equipo y nos gustaría que trabajen en sus componentes de interfaz de usuario sin preocuparse por la lógica de obtención de datos del resto del árbol de componentes. Relay adopta una postura concreta para resolver algunos de estos problemas que vale la pena entender y aprender de ellos. En esta charla, voy a motivar las características principales de Relay desde cero. Haré demostraciones prácticas para explicar los desafíos comunes a los que se enfrentan los clientes de GraphQL, cómo se podrían solucionar sin Relay y luego solucionarlos con Relay. También hablaré brevemente sobre cómo funciona Relay y su diseño, y cómo el objetivo de diseño de Relay no es solo ser un cliente de GraphQL de alto rendimiento, sino también aumentar la productividad y la felicidad de los desarrolladores.

27 min
02 Aug, 2021

Video Summary and Transcription

Esta charla analiza el uso de Relay y fragmentos en la obtención de datos para aplicaciones React. Explora los desafíos de obtener datos de los componentes y la optimización de la obtención de datos. La charla también aborda el uso de fragmentos para la obtención de datos de componentes y los desafíos y errores potenciales que pueden surgir. Destaca las decisiones de diseño de Relay que facilitan el acceso a los datos y el uso de variables en los fragmentos. La charla concluye con una discusión sobre la obtención de datos de fragmentos y la combinación de fragmentos y consultas en Relay.

Available in English

1. Introducción a Relay y Hasura

Short description:

Voy a hablar de enamorarse de Relay, mi viaje desde el escepticismo hasta la admiración. Me presentaré como el fundador y CEO de Hasura, una startup de tecnología de código abierto. Hasura proporciona un motor GraphQL que se conecta a tu base de datos y servicios, ofreciendo una API GraphQL unificada. Relay se encarga de lograr la mejor obtención de datos mientras se utiliza GraphQL. Utilizaré un ejemplo de un panel de datos para demostrar el poder de Relay en una aplicación de React.

Hola a todos. Estoy muy feliz de estar aquí. Espero que todos estén bien. Voy a hablar un poco sobre enamorarse de Relay. Así que este es mi viaje de ser escéptico sobre Relay como un cliente GraphQL y luego gradualmente enamorarme de él.

Mi nombre es Tanna Gopal, y antes de comenzar, les daré una breve introducción. Soy el fundador y CEO de Hasura. Hasura es una startup de tecnología de código abierto. Construimos un motor GraphQL que puede conectarse principalmente a tu base de datos y otros servicios para que puedas unificar tu API GraphQL. Se ejecuta como un contenedor Docker en tu propia infraestructura. Es de código abierto bajo la licencia Apache, y puedes consultarlo en GitHub. Gran parte de este trabajo y esta charla han sido motivados por el hecho de que hemos estado agregando soporte para Relay en Hasura, y al final te mostraré cómo puedes comenzar a jugar con Relay y Hasura.

Bien, ahora vamos a sumergirnos en Relay. Cuando piensas en GraphQL e integras GraphQL en tus aplicaciones, el mayor punto de venta de GraphQL es que, al menos para mí, fue la primera vez que encontré una API fácil de explorar e integrar, ¿verdad? Es como si pudiera ver cómo es la API, puedo autocompletarla, puedo entender cómo debo integrarla porque puedo ver los tipos, ¿verdad? Puedo integrarlo con mi sistema de tipos, lo que sea que esté usando en el lado del cliente. Y cosas así. Donde encaja Relay es que Relay se encarga de la responsabilidad o Relay facilita lograr la mejor obtención teórica de datos, ¿verdad? Que podemos lograr mientras usamos GraphQL y nos mantenemos cuerdos. Voy a hablar sobre el aspecto de mantenernos cuerdos, ¿verdad? Entonces, ¿cómo podemos, al usar GraphQL en nuestra aplicación, cuál es la mejor obtención de datos que podemos hacer al introducir la menor cantidad de carga en nosotros mismos como desarrolladores, ¿verdad? Ahí es donde encaja Relay. Y esto se volverá más claro a medida que avancemos y es por eso que Relay es increíble y las ideas detrás de Relay son realmente increíbles.

Para motivar o ver un ejemplo a lo largo de esta charla, lo que voy a hacer es tomar el ejemplo de un panel de datos, ¿verdad? Esta es una aplicación de front-end. Es una aplicación de React. Es un panel de administración de datos, ¿verdad? Puedes ver que hay tablas a la izquierda. Estoy mirando una tabla en particular. Esa tabla tiene columnas, esa tabla tiene una opción de filtrado, ¿verdad? Hay cosas así. Esta aplicación es en realidad la consola de Hasura, que es una aplicación de React. Pero en cualquier caso, imagina que esta es una aplicación de React de complejidad media, solo porque hay mucha obtención de datos sucediendo. Si miras los recuadros rojos que he resaltado aquí, déjame mostrarlo con mi puntero. Si miras estos recuadros rojos que he resaltado aquí, esos son los diferentes fragmentos de datos que estamos obteniendo de nuestra API. Aquí estamos obteniendo una lista de todas las tablas. Aquí estamos obteniendo información sobre esa tabla en particular. Aquí solo estamos mostrando el nombre de la tabla. Aquí estamos obteniendo una lista de todas las columnas para que podamos renderizar este menú desplegable y el tipo de columna para que podamos renderizar las operaciones en las que puedes filtrar esa columna.

2. Obtención de datos para la vista de tabla

Short description:

Aquí estoy obteniendo una lista de columnas para renderizar una vista de tabla. En la vista de tabla modificada, estoy viendo diferentes columnas y sus tipos en la base de datos. También estoy obteniendo una lista de atributos y, para un atributo, una cantidad mayor de datos. Para obtener estos datos y construir la aplicación, adjuntaría una consulta a cada componente de la interfaz de usuario.

Correcto. Y aquí estoy obteniendo una lista de todas las columnas para poder renderizar una vista de tabla. Correcto. Estas son las diferentes piezas de datos que necesito obtener para esta aplicación.

Veamos otra vista en la misma aplicación. Ahora estoy en una vista diferente. Estoy en la vista de tabla modificada. Correcto. Aquí estoy viendo las diferentes columnas y los tipos de esas columnas en mi base de datos. Correcto. Estoy enumerando todas las columnas diferentes. Estoy enumerando cuáles son los tipos de esas columnas. Correcto. Ya sea una columna de texto, una columna de caracteres o si es nula. Y luego, en un caso, una de las columnas en las que he hecho clic como usuario, tengo una vista expandida. En esta vista expandida, no estoy viendo solo dos propiedades de esta columna. Estoy viendo como cinco propiedades diferentes de esta columna. Correcto.

Así que estoy obteniendo una lista de atributos. Pero para uno de esos atributos, estoy obteniendo una cantidad mayor de datos. Correcto. Nuevamente, un escenario bastante típico que puedes imaginar en una aplicación. Correcto. Muy bien. Veamos cómo habríamos utilizado una API de GraphQL para obtener estos datos y construir esta aplicación. Correcto. La primera opción, lo más sencillo que podría haber hecho, es simplemente tomar cada componente de la interfaz de usuario y adjuntarle una consulta. Hago una consulta aquí para obtener las tablas. Hago una consulta aquí para obtener el nombre de la tabla para un ID en particular. Correcto.

3. Obtención de datos desde componentes

Short description:

Estoy obteniendo datos de diferentes componentes, lo que resulta en múltiples consultas. Este enfoque es fácil pero terrible porque genera un gran número de llamadas de red y consultas redundantes.

Tal vez estoy obteniendo este ID desde la URL o desde un componente en particular en el que se hizo clic. Correcto. Desde este componente en el que se hizo clic. Luego, creo otro componente para esta columna de filtro, una especie de interfaz de usuario en la que obtengo el nombre y el tipo de las columnas. Y aquí, para este tipo de explorador de tablas, hago una consulta para obtener los nombres de las columnas. Correcto. Así que estoy haciendo diferentes consultas. Es realmente fácil porque todos los data que necesito obtener están a nivel de componente. Correcto. Por lo tanto, la ventaja de tener una consulta por componente es que, ya sabes, es súper fácil. Correcto. Es modular, por así decirlo. En realidad, esto, por supuesto, de hecho, es una idea terrible porque estás haciendo un número tremendo de llamadas de red y va en contra de todo el propósito. Y, ya sabes, las cosas que la gente dice sobre GraphQL. De hecho, no solo hace muchas llamadas de red. Si observas esta interfaz de usuario detenidamente, verás que estoy haciendo muchas llamadas redundantes. Correcto. Estoy obteniendo el nombre aquí, que ya he obtenido aquí y obteniendo los nombres y tipos de las columnas aquí, que ya he obtenido aquí. Así que también estoy haciendo consultas redundantes. Correcto. Aparte de que estoy haciendo múltiples consultas, lo cual es terrible. Correcto.

4. Optimización de la obtención de datos

Short description:

La primera optimización consiste en realizar una consulta gigantesca que obtenga todos los datos necesarios para la página. Si bien teóricamente esta es la mejor consulta, resulta inconveniente para los desarrolladores que crean diferentes componentes, ya que los requisitos de datos para los componentes secundarios están dispersos en los componentes ancestros. Pasar props a los componentes secundarios se vuelve engorroso.

Entonces. Entonces, la primera optimización que puedo hacer. Correcto. La optimización más sencilla que puedo hacer es realizar una consulta gigantesca. Así que hago una consulta gigantesca para esta página. Correcto. Y teóricamente, esta es la mejor consulta que puedo hacer. Correcto. Así que hago una consulta. Obtengo todas las tablas y sus nombres para una tabla en particular que quiero mostrar. Obtengo el nombre de la tabla y obtengo el tipo de columnas, ya sabes, los nombres de las columnas que voy a mostrar aquí en el explorador de tablas y los tipos que voy a usar para mostrar los diferentes operadores. Correcto. Entonces, si es un entero, puedo hacer igual. Puedo hacer igual si es un booleano, mostraré verdadero, falso, lo que sea. Entonces. Esta es una consulta óptima que puedo hacer. Esto es bueno. Correcto. Esto es bueno, pero no me gusta esta idea porque aunque es óptima, como desarrollador que está construyendo así, como desarrollador que está construyendo estos diferentes componentes, es inconveniente porque los requisitos de data para un componente secundario, ¿verdad? Por ejemplo, una interfaz de usuario de columna de filtro o una interfaz de usuario de explorador de data, los requisitos de ese data están en algún lugar del ancestro. Correcto. Está en algún componente ancestro que tiene, que tiene esto, que está haciendo esta consulta. Correcto. Y luego voy a pasar todas las props a todos los componentes secundarios gradualmente. No es una experiencia muy divertida. Correcto.

5. Introducción de fragmentos para la obtención de datos del componente

Short description:

Puedo introducir fragmentos en lugar de tener una consulta gigantesca en el nivel superior. Cada componente hijo puede tener su propio fragmento que especifique los datos que necesita. Por ejemplo, el componente de encabezado de la tabla puede declarar un fragmento para el nombre, mientras que la interfaz de usuario del filtro puede tener un fragmento para las columnas y los tipos. Esto permite un control más granular sobre los datos obtenidos para cada componente.

Entonces, lo siguiente que puedo hacer es introducir fragmentos. Correcto. Así que lo que puedo hacer es, en lugar de tener una consulta gigantesca en el nivel superior, tendré una consulta en el nivel superior que haga referencia a diferentes fragmentos que tengo. Correcto. Entonces, cada vez que construyo un componente hijo, digamos que estoy construyendo el componente de encabezado de la tabla. Declaro un fragmento que dice, aquí hay un fragmento, quiero el nombre. Correcto. Si estoy construyendo la interfaz de usuario del filtro, diré, bueno, aquí hay un fragmento. Quiero todas las columnas, los nombres de las columnas y los tipos. Correcto. Así puedo renderizar esta interfaz de usuario. Si estoy construyendo este componente de explorador de tablas, básicamente solo obtengo los nombres de las columnas. Eso es todo lo que necesito para crear este encabezado de tabla. Correcto.

6. Uso de fragmentos en la construcción de componentes

Short description:

Declaro fragmentos junto con los componentes que construyo. Cada componente puede declarar los datos exactos que necesita. Sin embargo, el uso de fragmentos puede propiciar errores. Dos puntos problemáticos son la importación de fragmentos y el acceso de los componentes hijos a todos los datos. Por ejemplo, un componente hijo para votar en comentarios debe incluirse en el fragmento principal.

Entonces, declaro estos fragmentos junto con los componentes que construyo. Correcto. Digamos que tengo tres archivos aquí, en cada uno de estos archivos incluyo un fragmento. Correcto. Además, si estoy construyendo el componente ancestral, iré al componente de consulta ancestral en algún lugar. Correcto. Aunque estos componentes tienen una jerarquía. Tengo que incluir, ya sabes, este fragmento en el componente ancestral aquí o algo así. Correcto. Eso es más o menos cómo sería la experiencia con los fragmentos.

Los beneficios aquí son que es agradable porque, ya sabes, cada componente que construyo, puedo declarar los data. Puedo declarar exactamente los data que quiero. Sin embargo, los inconvenientes son que la experiencia de usar fragmentos no es particularmente buena. Y a menudo propicia errores. Voy a hablar de dos puntos problemáticos particulares en la integración básica de fragmentos. Correcto. El primero es la importación de fragmentos. Y el segundo es que todos los componentes hijos tendrán acceso a todos los data. Así que veamos qué significa esto.

Correcto. Entonces, el primero, y este es un ejemplo que he tomado de la página de documentación de fragmentos del cliente Apollo. Si miras a la izquierda aquí, estoy haciendo, tengo un componente hijo. Así que imagina que estos son comentarios y los comentarios tienen votos. Correcto. Y lo que estoy viendo es, estoy viendo el componente hijo donde estoy votando en un comentario en particular. Así que esto tiene un fragmento. Correcto. Y luego el padre tiene la consulta completa, o tal vez un fragmento padre, ¿verdad? Tiene un fragmento más grande que incluye este fragmento. Correcto. Entonces, esta parte es necesaria, ¿verdad? Necesito incluir mi fragmento hijo en el fragmento padre.

7. Importación de fragmentos y posibles errores

Short description:

Esta es la parte que resulta un poco irritante. Necesito incluir una importación de este fragmento como una variable dentro de este fragmento. Esto no es divertido porque tengo que asegurarme de incluir el fragmento dentro de mis componentes y también importarlo en el componente padre, lo que puede generar errores.

Correcto. Pero esta es la parte que resulta un poco irritante. ¿Verdad? Necesito declarar, necesito incluir una importación de este fragmento como una variable dentro de este fragmento. Esto es irritante, ¿verdad? Esto no es divertido. Porque ahora tengo que asegurarme de que no solo incluyo el fragmento dentro de mis componentes, sino que también, cada vez que escribo el componente padre, estoy importando el, también estoy importando ese fragmento e incluyendo ese fragmento aquí también, ¿verdad? Lo cual puedo olvidar hacer, o, ya sabes, pueden ocurrir todo tipo de cosas. Pueden haber errores.

8. Desafíos con el uso de fragmentos y paso de datos

Short description:

Si tengo fragmentos que incluyo en la consulta de nivel superior, todos los componentes tendrán acceso a más atributos de los necesarios. Pasar props a los componentes secundarios requiere cuidado para evitar errores. Para facilitar el uso de fragmentos, necesitamos importación y validación automática, así como optimizaciones para el paso de datos.

Correcto. Estos son un poco los, no es una experiencia ideal. Correcto.

Hay otro punto doloroso. El otro punto doloroso es que si tengo fragmentos que incluyo en la consulta de nivel superior, lo que sucederá es que todos estos componentes, los componentes de React donde, digamos, obtengo estos componentes y les asigno una variable para obtener los datos de la tabla, ¿verdad? Cuando obtengo estos datos y les asigno una variable, este componente terminará teniendo acceso, no solo al atributo de nombre que necesita, sino también al atributo de columnas y también a columnas.nombre y columnas.tipo. Correcto.

Y si observo el componente de filtro de columnas que solo necesita nombre y tipo, está bien. Tendré acceso a columnas.nombre y columnas.tipo, pero el componente de explorador de columnas que solo necesita acceso al nombre de la columna, también terminará teniendo acceso al tipo de columna. Correcto. Y debo tener cuidado con la forma en que paso estas props a mis componentes secundarios, desde la consulta principal que tengo. Correcto. Y requiere un poco de cuidado. Y si no tengo cuidado, lo que a menudo puede suceder, especialmente cuando estamos construyendo aplicaciones rápidamente, ya sabes, digamos que estoy construyendo este componente de explorador y me doy cuenta de que necesito acceso al tipo de columna. Tal vez olvidé actualizar el fragmento. Correcto. Tal vez necesito ir a tablas.tabla.columnas.tipo de todos modos, porque tengo acceso a eso. Correcto. Debido a algún otro fragmento que estaba usando. Sería negligente. Correcto. O podría ser negligente y olvidar incluir ese atributo en este fragmento aquí. Correcto. Solo porque alguien más lo estaba solicitando. Y este será el punto de partida de los errores tan pronto como tengamos un gran número de fragmentos. Entonces, si queremos facilitar el uso de fragmentos, lo que realmente queremos hacer es asegurarnos de que los fragmentos se importen y validen automáticamente a medida que los usamos en nuestros componentes. Y también queremos que ocurran optimizaciones cuando estamos pasando data. Correcto. Para que obtengamos algún tipo de aislamiento y modularidad en los componentes que estamos escribiendo. Correcto. Para que cuando sienta que estoy escribiendo un componente para un fragmento, sienta que solo tengo acceso a los datos que declaré en mi fragmento.

9. Decisiones de diseño de Relay para el acceso a datos

Short description:

Relay tiene dos decisiones de diseño que facilitan el acceso a los datos. Primero, tiene un compilador que se ejecuta como parte del proceso de compilación, asegurando que todos los fragmentos se importen y validen en tiempo de compilación. Segundo, al usar un fragmento en un componente, solo se puede acceder a los datos que están disponibles. Esto proporciona una forma conveniente de trabajar con fragmentos en Relay.

Correcto. Y aparte de eso, no tengo acceso a ningún otro data. A menos que se me pase explícitamente desde el componente padre. Correcto. Y si observas Relay, tiene dos decisiones de design que hacen que esto sea bastante fácil. La primera es que Relay no es solo un cliente de GraphQL que es una biblioteca que puedes incluir, crear consultas de GraphQL y hacer consultas de GraphQL, sino que Relay también tiene un compilador que hace posible que el compilador se ejecute como parte del proceso de compilación. Correcto. Se ejecuta en paralelo mientras realizas un flujo de trabajo de desarrollo. Y a medida que construyes fragmentos e importas consultas, todas las consultas, todos los fragmentos que se importan, todos los fragmentos que se validan, todo ocurre en tiempo de compilación para que no obtenga estos errores de tiempo de ejecución con la importación de fragmentos. Correcto. O por ejemplo, cuando pienso en el enmascaramiento de data, cuando uso el fragmento en mi componente, solo puedo usar los data a los que tengo acceso, que es la forma en que uso el contenedor de fragmentos dentro de Relay. Correcto.

10. Usando Fragmentos e Introduciendo Variables

Short description:

Cuando uso fragmentos con Relay, no necesito importarlos explícitamente en mi fragmento o consulta principal. Solo tengo acceso a los atributos declarados en mi fragmento. Esto asegura que obtenga los datos que necesito y evita errores. Sin embargo, a medida que comienzo a usar fragmentos, pronto necesitaré variables en mis fragmentos. Por ejemplo, en un panel de control, es posible que desee que los usuarios elijan ciertas opciones.

Para ver de manera tangible el trabajo que se me quita. No tengo que importar explícitamente fragmentos en mi fragmento principal o en mi consulta principal. Y cuando intento acceder a los data que mi componente en particular obtendrá. Correcto. Solo tendré acceso a aquellos atributos que he declarado en mi fragmento. Correcto. Aquí solo tengo acceso a table.name. Aquí solo tengo acceso a columns.name y columns.type. Y aquí solo tengo acceso a columns.name nuevamente. Correcto. Lo cual es bueno porque si intento acceder a alguna otra propiedad, obtendré un error en tiempo de compilación. Correcto. Lo cual es genial. Correcto. Entonces, cuando usas fragmentos con Relay, esto comenzará a funcionar automáticamente. Correcto. No quería entrar en más sintaxis para mostrarte cómo es la configuración, pero solo quería enfatizar en los conceptos que podrás usar. Muy bien.

El siguiente problema con el que te encontrarás al comenzar a usar fragmentos. Correcto. Los fragmentos son buenos. Estoy usando fragmentos en todas partes. Es genial. Mis componentes son modulares. Correcto. Pero el siguiente problema con el que me encontraré es que pronto necesitaré variables en mis fragmentos. Correcto. Entonces, lo que necesitaré es hablar sobre un ejemplo simple. Digamos que en este tipo de panel de control que tengo. Quiero que los usuarios elijan.

11. Usando Variables en Fragmentos

Short description:

Quieres que los usuarios puedan ver solo las primeras tres columnas. Si deseas usar una variable en un fragmento, debes declararla en el nivel superior, lo cual puede ser incómodo porque estas variables pertenecen a lo más profundo de la jerarquía de componentes y provienen de la entrada del usuario.

Sabes que quiero que los usuarios puedan ver solo las primeras tres columnas. Tal vez tenga una tabla de 1,000 columnas. Correcto. Y solo quiero ver las primeras tres columnas. Correcto. Entonces tal vez quiero hacer un límite, es decir, quiero obtener solo las primeras tres. Correcto. Solo quieres las primeras tres columnas. Correcto. Y si eso es lo que quieres, te darás cuenta de que necesitas tener una variable que este fragmento en particular tenga. Correcto. Tal vez este componente en particular tenga algo como una interfaz de usuario que diga, ¿cuántas columnas quieres ver? Quiero ver tres. Quiero ver diez. Entonces elijo la cantidad de columnas que quiero ver y eso se convierte en una variable proporcionada por el usuario. Correcto. Para hacer el fragmento.

La cosa es que esto obviamente es posible de hacer. Esta es una sintaxis válida. Pero si quiero usar una variable en un fragmento, debo declararla en el nivel superior. Correcto. Eso significa que si necesito usar una variable en un fragmento en algún lugar profundo de mi jerarquía de componentes, debo declarar esa variable en la consulta de nivel superior. Correcto. Porque necesito declarar variables de consulta, lo cual, como puedes imaginar, es un poco irritante. Correcto. Porque estas variables pertenecen a algún lugar profundo en la jerarquía de componentes. Estas variables provienen de la entrada del usuario. Estas variables no pertenecen a un componente ancestro. Correcto. Imagina si volviéramos a nuestro diseño de consulta original. Correcto.

12. Declarando Variables para Fragmentos Localmente

Short description:

Si tuviera una consulta por componente, estaría realizando una cantidad absurdamente grande de solicitudes, pero podría declarar exactamente las variables que necesito. Me gustaría declarar variables para mis fragmentos localmente, a nivel de fragmento, y usarlas allí. Relay proporciona un concepto de diseño de tener argumentos y definición de argumentos, lo que te permite definir y declarar localmente una variable en un fragmento sin modificar la consulta de nivel superior. Esto es realmente genial.

Si tuviera una consulta por componente, estaría realizando una cantidad absurdamente grande de solicitudes, pero podría declarar exactamente las variables que necesito, ya sabes, cuando las necesito. Correcto. Lo cual es, lo cual es genial. Entonces, si, si la forma en que esto funciona en Relay es, la forma en que esto funciona en Relay es lo que me gustaría hacer es poder declarar variables para mis fragmentos localmente. Correcto. Me gustaría declararlas a nivel de fragmento y me gustaría poder usarlas también a nivel de fragmento. Y aquí es donde un concepto de diseño de Relay de tener argumentos y definición de argumentos. Estos son directivas del lado del cliente y dos directivas del lado del cliente que puedes agregar a cualquier fragmento para definir y declarar localmente una variable, en ese mismo lugar, correcto. A nivel de fragmento sin tener que ir a la consulta de nivel superior y modificar eso. Y eso es realmente genial. Y veremos un ejemplo pronto. Correcto. Y veremos un ejemplo de cómo se ve la sintaxis pronto. Pero por ahora, en el próximo, en el siguiente ejemplo de IU que veremos.

13. Manejo de Variables Localmente y Actualización de Fragmentos

Short description:

Necesitamos una forma de manejar variables localmente y actualizar fragmentos cuando el usuario proporciona información. Por ejemplo, al paginar a través de una lista, las variables utilizadas para obtener la lista cambian y queremos volver a obtener la lista sin ejecutar toda la consulta nuevamente. Este deseo de consultas casi para cada componente conduce a la necesidad de modularidad de fragmentos y la capacidad de ciclo de vida independiente de las consultas.

Pero por ahora, ten en cuenta que necesitamos alguna forma de poder manejar variables localmente. Correcto. Entonces, tan pronto como te des cuenta de que quieres manejar variables localmente, te das cuenta de que en realidad lo que querías hacer era cada vez que el usuario proporciona información en algún lugar en lo profundo de la jerarquía de componentes, ¿verdad?, lo que quieres hacer es actualizar ese fragmento. Correcto. Entonces, si observas ese tipo de ejemplo en el que quería ver solo tres columnas, tal vez el usuario nos proporcione más información y quiero ver solo 10 columnas. Y a medida que el usuario nos proporciona información, queremos actualizar solo ese fragmento y no queremos volver a ejecutar, definitivamente no queremos ejecutar toda la consulta nuevamente. Correcto. Eso es lo que queremos hacer. Correcto. Entonces, queremos utilizar la modularidad de los fragmentos. Pero queremos tener casi la capacidad de ciclo de vida independiente de una consulta. Correcto. Y veamos un ejemplo un poco más tangible. Correcto. Entonces, en las aplicaciones que estás construyendo, frecuentemente verás esto cuando se trata de la paginación. Correcto. Cuando quieres paginar, tienes un componente hijo que está renderizando una lista. Correcto. Y a medida que paginas, las variables que estás utilizando para obtener esa lista, esas variables están cambiando. Correcto. Y esas variables están cambiando según la demanda. Ahora, cuando esas variables cambian, quieres volver a obtener la lista. No quieres ejecutar toda la consulta nuevamente. Correcto. Ese es el tipo de cosa del que estaba hablando, que es como un caso de uso de expansión. Correcto. O un caso de uso de `leer más`. Y como dije, esto es como querer tener consultas casi para cada componente. Correcto. Entonces, veamos un ejemplo tangible y cómo se ven las consultas.

14. Obtención de Atributos Expandidos

Short description:

Tengo una lista donde quiero ver más información sobre un atributo cuando el usuario hace clic en expandir. Por defecto, solo quiero dos atributos para cada elemento de la lista, pero si se expande, quiero cinco atributos. Ejecuto una consulta para obtener todas las columnas, donde obtengo información mínima como el nombre y la descripción. Si un elemento se expande, quiero mostrar atributos adicionales. Esto se logra definiendo una variable a nivel de fragmento y utilizando definiciones de argumentos. En la carga inicial, el valor predeterminado es falso y cuando el usuario hace clic en expandir, se vuelve a ejecutar el fragmento.

Aquí estoy viendo un ejemplo similar, donde tengo una lista. Correcto. Y cuando el usuario hace clic en expandir, quiero ver más información sobre este atributo. Por defecto, solo quiero dos atributos para cada elemento de la lista. Y si lo expando, quiero cinco atributos para ese elemento de la lista. Correcto. Y esto es para el panel de control que estamos construyendo. Correcto.

Entonces, si pienso en esto, lo que quiero hacer es ejecutar una consulta para obtener todos los elementos. En este caso, los elementos son columnas. Quiero obtener todas las columnas. Correcto. Por ejemplo, quiero obtener información mínima por columna. Veamos cuál es la información mínima aquí. Solo quiero obtener el nombre y la descripción. Estos son los dos atributos que quiero mostrar en caso de que uno de los elementos esté expandido. Quiero poder mostrar información expandida para esa columna en particular. Y ahora veamos la forma expandida. Quiero ver el nombre y otros 10 atributos. Y esta es una variable que se define a nivel de fragmento. Estoy utilizando definiciones de argumentos para definir una variable en este fragmento y decir que, al renderizar esta lista, si esta variable es verdadera para esta columna en particular, también quiero incluir este fragmento en particular. En la carga inicial, el valor predeterminado será falso. Por lo tanto, en la carga inicial, obtendremos todos los elementos con solo el nombre y la descripción. Cuando el usuario hace clic en expandir, es cuando quiero volver a ejecutar este fragmento.

15. Volver a ejecutar y volver a obtener datos de fragmentos

Short description:

Quiero volver a ejecutar y volver a obtener los datos de un fragmento solo si está expandido. Esto se puede lograr haciendo que el fragmento sea recuperable y utilizando la función de refetch con la variable establecida en true. El fragmento se ejecutará como una consulta con la variable establecida en true, lo que permitirá la recuperación de datos específicos. Este proceso ocurre cuando el fragmento está expandido.

Pero obtener más data para este fragmento. Correcto. Eso es, eso es más o menos lo que quiero hacer, ¿verdad? Quiero volver a ejecutar y volver a obtener los data para este fragmento en particular, solo si lo expandimos es verdadero para obtener más data, ¿verdad? Y, y realmente, eso es tan simple como ir a un fragmento en particular y decir, hagamos que este fragmento sea recuperable. Y cada vez que haya un clic o un evento de usuario, ejecutaremos una función llamada refetch, que es una función que tienes en un fragmento con la variable establecida en true. Entonces, este fragmento se ejecutará como una consulta, ¿verdad? Se ejecutará como una consulta con esta variable establecida en true para que puedas obtener exactamente estos data, ¿verdad? Y eso sucederá solo para esa columna, ¿verdad? Un caso en el que hago clic en expandir, ¿verdad?

16. Re-fetching de fragmentos y API de Relay

Short description:

Los fragmentos en Relay no pueden ejecutarse de forma aislada y deben formar parte de una consulta más grande. Para habilitar el re-fetching de fragmentos, una API compatible con Relay implementa una interfaz de nodo con un ID globalmente único. Cuando se vuelve a obtener un fragmento, el cliente solo ejecuta la consulta para ese elemento específico, utilizando el ID único y los campos solicitados. Este enfoque combina la conveniencia de usar fragmentos con la capacidad de tratar cada fragmento como una consulta.

Y esto es realmente interesante, ¿verdad? Esto es, si piensas en cómo funciona en el fondo, si piensas en la ergonomía, es como, oh, este fragmento es como una consulta, así que puedo ejecutar esta consulta de nuevo. Ese es un proceso de pensamiento conveniente, ¿verdad? Pero en realidad, no es fácil hacer que funcione porque un fragmento no puede ejecutarse de forma aislada, ¿verdad? Un fragmento necesita ejecutarse como parte de una consulta más grande. Entonces, ¿cómo puede ejecutarse un fragmento por sí mismo? Y el secreto aquí es que una API de Relay normalmente implementa una interfaz de nodo y una resolución raíz de cualquier nodo. Entonces, una API compatible con Relay, bueno, ya no es obligatorio, es opcional, es que cada elemento que estás obteniendo tiene una interfaz o implementa una interfaz llamada nodo y tiene un ID globalmente único, ¿verdad? Y tu API de Relay GraphQL tiene un resolvedor raíz para obtener cualquier nodo solo por su tipo de GUID, su ID globalmente único. Entonces, lo que Relay puede hacer es que cuando marco o solicito al cliente que vuelva a obtener un fragmento en particular, el cliente no tiene que ejecutar toda la consulta de nuevo. El cliente solo vuelve a ejecutar la consulta para esa columna o ese elemento en particular que quiero volver a ejecutar. Y el cliente puede hacer eso porque cada elemento es una instancia de nodo y cada elemento tiene un ID único. Entonces, la consulta que se está ejecutando en segundo plano es en realidad consulta, elemento, ID único y los campos exactos que quiero. Entonces, en nuestro ejemplo particular, hay una consulta en segundo plano que se ejecuta cada vez que hacemos un re-fetch. La consulta que se está ejecutando, la consulta subyacente de GraphQL que se está ejecutando es una consulta en la columna donde el ID es igual al ID actual para esta columna que estoy renderizando, que es un ID geo que tengo. Y está obteniendo los campos nombre, descripción, tipo, anulable, único, predeterminado, lo que sea. Como está obteniendo los diferentes atributos que quiero. Y esto es realmente bueno. Obtengo la conveniencia de usar fragmentos, ¿verdad? Pero al mismo tiempo, obtengo la capacidad de tratar cada fragmento como una consulta. Y esto es realmente conveniente. Entonces, para resumir, si comienzas a mirar Relay, puede ser un poco abrumador. Si miras la documentación de Relay, si escuchas a las personas hablar de Relay, hay mucho sucediendo. No te preocupes demasiado por eso. Piensa en la modularidad que deseas en tu aplicación como la modularidad que puedes lograr con un buen enfoque basado en fragmentos. A medida que comienzas a pensar en esa modularidad y comienzas a pensar en usar fragmentos en la práctica, notarás que tendrás que reconstruir muchas de las mismas decisiones de diseño que Relay te impone desde el principio, ¿verdad? Por ejemplo, nombres únicos de fragmentos que nos permiten importar fragmentos automáticamente, ¿verdad? Tener directivas del lado del cliente que nos permitan declarar variables para fragmentos, tener la interfaz de nodo y un ID global único que nos permita volver a obtener y volver a ejecutar fragmentos según la demanda, eso facilita la paginación, facilita cosas como expandir un elemento, ¿verdad? Hace que todas esas interacciones sean más fáciles. Así que hoy estoy lanzando, hoy hemos estado trabajando muy duro en esto durante las últimas semanas, es que puedes probar Relay con Hasura. Así que ve a hasura.io/GraphQL/Relay. Todo lo que necesitas hacer es implementarlo en Heroku si solo quieres probar las cosas, configurar tu base de datos, hacer un poco de modelado de datos, establecer algunas relaciones entre estos modelos de datos que tienes, configurar las reglas de permisos, y obtendrás una API de Relay instantáneamente que puedes comenzar a usar e integrar. Y luego, por supuesto, más allá de las API de tipo CRUD que obtienes, una vez que quieras comenzar a agregar lógica de negocio personalizada, puedes agregarla en tu lenguaje favorito también, Node.js o Python o Ruby o lo que quieras, y desplegarlas en funciones sin servidor o donde sea, y eso se agregará a tu API de GraphQL con Hasura también. Y podrás probar Relay. Así que pruébalo. Danos tu opinión. Está en beta y deberíamos poder lanzarlo de manera estable muy, muy pronto. Para esta charla en particular, necesité mucha persuasión y comprensión, y obviamente la documentación de Relay ayuda, pero dos personas que me ayudaron especialmente fueron Gabriel y Sean, definitivamente deberías seguirlos en Twitter en ZTH y sgrove. Y también tienen dos publicaciones de blog muy buenas que han escrito juntos sobre Relay, que hablan sobre el cliente de GraphQL que hace el trabajo listo para ti y hablan sobre la paginación. Así que también deberías echarle un vistazo. Eso es todo de mi parte. Soy Tamay. Puedes encontrarme en Twitter. No dudes en contactarme si tienes alguna pregunta sobre GraphQL, Hasura, Relay y haré todo lo posible para responderlas o conectarte con personas que puedan responderlas. Gracias. Eso es todo de mi parte.

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

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
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 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. 
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.
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.
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 Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Top Content
Featured WorkshopFree
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 🤐)
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
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 Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
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 Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
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.
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
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.
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Top Content
Featured Workshop
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