Esto es MUCHO mejor que NextJS (TanStack Server Components)

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

Transcript

00:00:00Componentes de servidor de React. Ámalos u ódialos. Parece que últimamente hay más odio que
00:00:04amor, pero eso podría cambiar porque TanStack ha entrado en juego. Así es, ahora tenemos
00:00:08componentes de servidor de TanStack y han adoptado un enfoque bastante diferente al de Next.js. Vamos a verlo.
00:00:13Comenzaré con un párrafo de su publicación de anuncio que creo que tranquilizará a
00:00:21mucha gente. Dice: "La mayoría de la gente ahora piensa en los componentes de servidor de React de una manera
00:00:26donde el servidor es lo primero. El servidor es dueño del árbol, useClient marca las partes interactivas, y las convenciones
00:00:31del framework deciden cómo encaja todo. Esto convierte a los componentes de servidor de React de una
00:00:35primitiva útil en algo alrededor de lo cual tiene que orbitar toda tu aplicación. No creemos que debas tener que
00:00:40adoptar ese modelo completo por adelantado solo para obtener el valor de los componentes de servidor de React".
00:00:45Esencialmente, lo que dicen es que no quieren seguir la ruta de Next.js, donde es
00:00:48componentes de servidor por defecto y luego necesitas la directiva useClient donde quieres tener
00:00:52interactividad. En cambio, TanStack quiere pensar en ello como: ¿qué tal si pudieras usar componentes de servidor de React
00:00:57de forma tan granular como pudieras obtener JSON en el cliente? Con ese objetivo en mente, echemos un vistazo a
00:01:01cómo implementaron realmente los componentes de servidor porque, alerta de spoiler, realmente me gusta la forma en que
00:01:06lo hicieron. Lo que tengo aquí es una aplicación normal de TanStack Start, así que todo por el momento va a
00:01:10ser un componente de cliente y lo único que he hecho son algunos pequeños pasos de instalación necesarios para
00:01:15hacer funcionar los componentes de servidor, que es esencialmente solo instalar algunos paquetes y modificar tu
00:01:18vconfig. Así es como se ve la página actualmente, tenemos nuestro componente de saludo aquí, que
00:01:22debería ser actualmente un componente de cliente y en el código es literalmente solo un único componente de React
00:01:27luego aquí abajo tenemos una ruta normal de TanStack y estamos usando el componente de saludo aquí. Ahora, supongamos que
00:01:32en nuestro componente de saludo quisieras hacer algo de lógica en el servidor. En mi caso, quiero obtener el
00:01:36nombre de host del sistema operativo y también algunas variables de entorno que solo están disponibles en el servidor
00:01:40solo para mostrarles que esto realmente se está ejecutando allí. En este momento, si intento usar os.hostname
00:01:45no va a funcionar, ya que esta es una función de Node y no está disponible en el navegador.
00:01:49Lo que necesitamos hacer entonces es tomar nuestro componente de saludo y renderizarlo en el servidor y el
00:01:53primer paso para hacerlo en TanStack Start es con una simple función de servidor. Como pueden ver, tengo
00:01:58una aquí llamada get greeting y todo lo que estamos haciendo dentro es usar la nueva función render server
00:02:01component, poniendo nuestro componente dentro de ella y devolviendo el componente de servidor renderizable
00:02:06que obtenemos. Pueden pensar en esto como algo tan simple como crear una solicitud GET para nuestro componente.
00:02:10Luego, todo lo que necesitamos hacer es simplemente obtener el componente de la función de servidor que creamos
00:02:14y podemos hacerlo dentro de un cargador (loader) en una ruta aquí, así que simplemente esperamos (await) get greeting y luego
00:02:18devolvemos eso también y sigue siendo un componente de servidor renderizable. Luego podemos usar eso dentro de
00:02:23nuestra ruta aquí usando use loader data y simplemente usamos el componente aquí abajo como esto. Con eso,
00:02:27ahora tenemos nuestro primer componente de servidor de TanStack. Pueden ver que os.hostname ahora está funcionando y también está
00:02:32obteniendo variables de entorno que solo están disponibles en el servidor. Ahora, lo que
00:02:36absolutamente me encanta de esta implementación es que, si se fijan, lo único nuevo aquí es la función render
00:02:41server component. El resto de esto era solo TanStack Start normal. Podrías reemplazar esto
00:02:46con simplemente algunos datos JSON siendo devueltos y los obtendrías de la misma manera. También creo
00:02:51que esta implementación es muy explícita sobre dónde se está ejecutando realmente tu código. Lo haces todo
00:02:55dentro de una función de servidor, así que está bastante claro que se ejecutará en el servidor y también
00:02:59dentro del render server component. De hecho, creo que puedo mejorar mi código de demostración aquí simplemente
00:03:03tomando las funciones que estamos ejecutando aquí arriba y que quiero ejecutar en el servidor, poniéndolas
00:03:07dentro de la función de servidor y luego simplemente pasando esos valores a mi componente de saludo como props, así
00:03:12ahora mi componente de saludo es esencialmente solo un componente simple que puede ser utilizado en el
00:03:16cliente o en el servidor. Estoy ejecutando toda la lógica que quiero ejecutar en el servidor dentro de mi
00:03:21función de servidor aquí. Nuevamente, es bastante explícito que eso se ejecutará en el servidor. Esto
00:03:25literalmente se siente como el polo opuesto de la lógica utilizada en Next.js y me encanta.
00:03:30Significa que puedo pensar en React de una manera normal, todo es primero cliente y luego añadir componentes de servidor
00:03:34encima cuando los quiero. ¿Pero qué pasa si quisiera usar un componente de cliente dentro de mi componente de servidor,
00:03:38o sea, anidado dentro del árbol? Digamos que quisiera añadir un botón de contador aquí que cada vez que
00:03:43hacemos clic solo añade al contador. Bueno, si simplemente intento añadir esto en mi componente de servidor aquí con
00:03:47un onClick y luego también una llamada a useState, pueden ver que se rompe por completo. Dice que useState no es
00:03:52una función o que su valor de retorno no es iterable y eso es porque greeting se está utilizando como un componente
00:03:56de servidor. No podemos usar esta funcionalidad de cliente. Para solucionar esto, tienes dos opciones y la segunda
00:04:01opción es definitivamente la mejor a usar, pero la primera opción les resultará familiar a aquellos
00:04:05de ustedes que han usado Next.js. Podemos simplemente mover esa lógica a su propio componente y luego usar la
00:04:10directiva use client. Esto funciona en los componentes de servidor de TanStack Start, podemos simplemente usar el
00:04:14componente dentro del componente de servidor ahora y, como pueden ver, todo funciona bien. La desventaja
00:04:18de este enfoque, sin embargo, es que ahora tenemos un componente de servidor controlando la renderización de un
00:04:22componente de cliente y esto puede empezar a ser un poco desordenado, es decir, si quisiera averiguar dónde estaba mi
00:04:28componente de contador en el árbol, iría a mi ruta aquí y vería que tenemos un componente de servidor greeting,
00:04:32luego volvería al componente de servidor greeting y dentro del componente de servidor vería
00:04:37que tenemos un componente de cliente y este desorden realmente puede empezar a acumularse y simplemente hacer que ese límite
00:04:42entre servidor y cliente se vuelva un poco confuso. TanStack no se conformaría con eso, sin embargo. Se
00:04:47preguntaron: ¿qué pasa si el servidor no necesita decidir ninguna parte de la UI con forma de cliente en absoluto?
00:04:51Y esto los llevó a crear algo completamente nuevo: componentes compuestos (composite components). Para usar uno, lo primero
00:04:56que haré es eliminar nuestro componente de cliente de nuestro componente de servidor y simplemente lo reemplazaré
00:05:00con cualquier hijo (children) de nuestro componente greeting. A continuación, también necesitamos cambiar lo que estamos devolviendo de
00:05:05nuestra función de servidor aquí. En lugar de devolver un componente de servidor renderizable, necesitamos devolver
00:05:09lo que se llama una fuente compuesta (composite source). Para hacer eso, podemos usar nuestra segunda función de ayuda
00:05:14de componente de servidor de TanStack: create composite component. Aquí, esencialmente solo estamos construyendo un componente
00:05:18donde las props aquí se consideran las ranuras (slots). Solo estoy usando una ranura de children muy simple, así que
00:05:22va a pasar cualquier cosa que pongamos como hijo de mi componente compuesto a este props.children, que
00:05:27estoy pasando al componente greeting que acabamos de tener. Con eso, de nuevo, lo que necesitamos hacer es
00:05:31simplemente obtener nuestro componente compuesto de nuestra función de servidor y lo hacemos de la misma manera en
00:05:36el loader aquí. Verán que solo estoy renombrando source a greeting, luego lo cargo con use loader
00:05:41data. La única diferencia aquí, sin embargo, es que no podemos usar esto como un componente. Verán que está lanzando un
00:05:45error aquí. Para renderizar realmente un componente compuesto, necesitamos usar el componente de ayuda
00:05:49CompositeComponent que obtenemos de los componentes de servidor de TanStack y, como prop source, pasamos
00:05:53el componente compuesto que obtenemos de nuestra función de servidor que creamos anteriormente.
00:05:57Con eso, mi componente de servidor ahora se está renderizando como lo teníamos antes y también estoy pasando
00:06:01el contador como hijos de este componente compuesto y eso se está pasando al greeting donde
00:06:05lo teníamos configurado aquí, así que lo está pasando a props.children, por lo que todo funciona ahora
00:06:10muy bien. También puedo ir a mi componente de contador y eliminar la directiva que teníamos aquí, ya que eso ya
00:06:14no es necesario porque sabe que este va a ser un componente de cliente ya que está dentro de un componente
00:06:18compuesto. Esto se está utilizando como una ranura. Ahora, podría parecer que obtuvimos el mismo resultado
00:06:23pero con más trabajo que solo usar la directiva use client, pero el poder realmente proviene de la
00:06:27experiencia de desarrollo y es un poco un cambio respecto al modelo use client. En lugar de tener nuestro
00:06:32servidor decidiendo dónde se renderizan nuestros componentes de cliente, como cuando teníamos el componente de contador dentro
00:06:36del propio componente de servidor, en cambio, lo que estamos haciendo con los componentes compuestos es decir: oye,
00:06:40va a haber una ranura aquí, vamos a renderizar un componente de cliente, pero el
00:06:44propio componente de servidor no tiene idea de qué será eso. Lo añadimos más tarde en nuestro código de cliente,
00:06:48así que manejamos todos los componentes basados en el cliente dentro del propio código de cliente. Eso es solo el comienzo también
00:06:53si echamos un vistazo a una página más compleja como esta, la de una publicación, donde esta publicación está siendo renderizada en el servidor,
00:06:58hay dos problemas que quiero resolver. El primero es que quiero añadir algunas acciones como
00:07:03darle me gusta a la publicación y seguir al autor, pero quiero añadirlas encima del título aquí y quiero
00:07:08usar un componente de cliente. En este momento simplemente estoy usando este patrón de ranura de hijos (children slot), lo que significa que si
00:07:12añadiera mis acciones de publicación aquí abajo, simplemente irían donde están los comentarios, ya que así es como tenemos
00:07:17configurado el componente, así que quiero alguna forma de decirle a mi componente de servidor dónde poner componentes de cliente
00:07:22específicos. Luego tenemos un segundo problema, que es si tengo un botón de seguir autor. En este momento, esta
00:07:27página de publicación realmente no tiene idea de quién es el autor. De hecho, descargamos toda esa lógica en
00:07:32el propio componente de servidor. Si quisiera obtener el autor en un componente de cliente aquí abajo, tendría
00:07:37que obtener el JSON de la publicación y obtener el autor de esa manera, y ese no es realmente un gran
00:07:42patrón, estaríamos haciendo una doble solicitud de datos. Por suerte para nosotros, TanStack realmente tiene otros dos tipos de ranuras
00:07:46que podemos usar en un componente compuesto además de esta de children, y la primera va a
00:07:50ser render props. Esto es esencialmente cualquier prop que sea una función que devuelve un elemento de React, así que
00:07:56esto puede llamarse como sea, no tiene que llamarse render actions, y aquí solo estoy diciendo qué
00:07:59datos quiero que pase el componente de servidor y eso será el id de la publicación y el id del autor.
00:08:04Ahora todo lo que necesitamos hacer en nuestro componente compuesto es simplemente usar esta función que estamos pasando
00:08:08como prop donde quieras que esté el componente que eventualmente se va a renderizar.
00:08:12En mi caso, quiero que sea debajo del encabezado de la tarjeta, así que puedo llamarlo con props.render
00:08:16actions, podemos usar un opcional, así que si no se pasa, no se rompe, simplemente no se
00:08:20renderizará, luego también podemos pasar la información que queremos del componente de servidor
00:08:24a nuestro componente de cliente. Después de esto, nuestro componente compuesto va a aceptar la prop render actions
00:08:28que acabamos de crear y para el valor simplemente pasamos una función que tiene un id de publicación
00:08:32y un id de autor como argumento, que el servidor va a rellenar, luego simplemente renderizamos nuestro
00:08:36componente de cliente post actions y podemos pasar esos datos a través de las props. Así que ahora tengo un botón
00:08:41aquí arriba donde puedo dar me gusta y copiar el enlace a la publicación y también hacer clic en seguir autor aquí, donde
00:08:45es consciente del nombre del autor, a pesar de que en realidad nunca lo he obtenido en esta página.
00:08:49Solo lo obtengo en el componente de servidor y el componente de servidor está pasando esos datos al
00:08:53componente de cliente por mí. Ahora, podrías pensar que esto rompe la lógica que teníamos antes, donde dijimos que
00:08:57no queremos que ningún componente de servidor esté a cargo de renderizar los de cliente, pero no lo hace, y eso es
00:09:01porque las ranuras (slots) son en realidad opacas. El componente de servidor aquí arriba no tiene idea de qué hay dentro de
00:09:06esto, solo sabe que algo va aquí y que necesita pasar estos valores, que en
00:09:10este caso es el id de la publicación y el id del autor. Esta función no se ejecuta en el servidor, en cambio, el
00:09:15servidor simplemente ve que necesita pasar datos y luego, en nuestro cliente, es cuando
00:09:19la función se ejecuta realmente y el componente se renderiza. Exactamente lo mismo se aplica a
00:09:23nuestro tercer tipo de ranura, que es component props, esta es en realidad un poco más simple que las
00:09:28render props, todo lo que estamos haciendo es, en lugar de tener una función que luego devuelve nuestro componente de cliente,
00:09:33simplemente pasamos el componente de cliente como una prop en sí misma, luego en nuestro componente compuesto
00:09:38en la definición aquí arriba estamos diciendo que queremos aceptar una prop que sea un componente de React que tenga
00:09:42las props de id de publicación e id de autor, luego podemos usar esto dentro del componente mismo. Puedes pensar en
00:09:47component props como un marcador de posición, el componente de servidor sabe que va a haber un componente
00:09:51ahí que necesita algunos datos, en nuestro caso el id de la publicación y el id del autor, pero realmente no le importa qué es ese
00:09:56componente, siempre y cuando acepte esas props, así que cambié mi componente post actions aquí abajo a
00:10:01otro que hice llamado fake post actions y luego guardamos eso, pueden ver que esto
00:10:05todavía se va a renderizar porque es el cliente el responsable de renderizar este componente,
00:10:10es solo el servidor el que proporciona los datos, mirando la documentación no parece que haya
00:10:14ninguna diferencia real en qué enfoque tomes, ya sea que vayas con component props o render props,
00:10:18podría reducirse solo a preferencia, la única diferencia que puedo ver es que tal vez quieras
00:10:22modificar los datos que obtienes del servidor, así que en este caso podemos hacer lo que queramos con
00:10:26el id de la publicación y el id del autor, ya que es solo una función y luego podemos pasar eso a nuestro componente
00:10:31mientras que si estás usando component props, simplemente pasas el componente mismo y el servidor
00:10:36maneja el paso de las props, ahora eso es lo básico de los componentes de servidor de TanStack, pero hay
00:10:40todavía mucho más para disfrutar, por ejemplo, si quisieras que la mayor parte de tu página fuera renderizada en el servidor,
00:10:44tal vez tienes un componente de encabezado, un componente de contenido y uno de pie de página y los quieres todos renderizados en el servidor,
00:10:49no tienes que agruparlos todos en una sola función render server component, en realidad puedes
00:10:53usar Promise.all, dividirlos en tres funciones diferentes y luego simplemente devolverlos como un objeto
00:10:58desde una única función de servidor, pero ¿qué pasa si uno de esos componentes tarda mucho en cargar? Eso significaría
00:11:03que toda la función de servidor y, por lo tanto, toda la página lo haría, bueno, no se preocupen ahí tampoco,
00:11:07lo que realmente podemos hacer es, en lugar de esperar la función render server component, podemos
00:11:12devolver la promesa que crea y luego en el cliente podemos aprovechar el hook use y
00:11:16los límites de Suspense para cargar esqueletos, así que los componentes de servidor simplemente cargarán cuando estén listos.
00:11:21Realmente me gusta el enfoque que TanStack ha tomado aquí, no se siente intrusivo, no me fuerzan
00:11:25a adoptarlo y puedo adoptarlo sin ninguna solución alternativa extraña, además cuando realmente voy a usarlo
00:11:31los componentes de servidor en sí mismos son en realidad solo tres funciones nuevas, el resto es solo simple
00:11:36funciones de servidor de TanStack Start, algo que ya estaba usando, y es tan simple como obtener
00:11:41datos. Esto también significa que se integra muy bien con herramientas como TanStack Query, algo que definitivamente
00:11:45haré, y también hace que cosas como el almacenamiento en caché sean más simples, si quisieras podrías literalmente
00:11:49simplemente guardar en caché la respuesta de la solicitud GET en tu CDN, definitivamente voy a explorar esto más,
00:11:54así que háganme saber en los comentarios de abajo qué piensan de ellos y si les gustaría ver más videos sobre ellos
00:11:59bueno, sí, suscríbanse y como siempre, nos vemos en el próximo.

Key Takeaway

TanStack Start ofrece un modelo de componentes de servidor React explícito y granular mediante el uso de 'composite components', permitiendo integrar lógica de servidor sin las restricciones de arquitectura impuestas por frameworks como Next.js.

Highlights

TanStack Start implementa componentes de servidor React de manera opcional y granular, diferenciándose del modelo obligatorio de Next.js.

La implementación utiliza funciones como 'renderServerComponent' y 'createCompositeComponent' para ejecutar lógica en el servidor sin obligar a toda la aplicación a orbitar alrededor de ese modelo.

El uso de componentes compuestos permite renderizar componentes de cliente dentro de componentes de servidor de forma opaca, evitando la necesidad de la directiva 'use client' en el componente principal.

TanStack permite inyectar datos del servidor a componentes de cliente mediante 'render props' o 'component props', evitando solicitudes de datos redundantes.

La carga asíncrona de componentes de servidor es posible combinando 'Promise.all' con el hook 'use' y los límites de 'Suspense' para manejar estados de carga.

Timeline

Enfoque de TanStack frente a Next.js

  • TanStack Start evita el modelo 'servidor primero' obligatorio de Next.js.
  • Los componentes de servidor se implementan de forma tan granular como la obtención de JSON en el cliente.

El framework propone un modelo donde el cliente es la prioridad y los componentes de servidor se añaden selectivamente. La implementación permite ejecutar lógica de Node.js, como acceder al nombre de host del sistema o variables de entorno, de manera explícita dentro de funciones de servidor dedicadas.

Implementación de componentes de servidor y compuestos

  • La función 'renderServerComponent' convierte un componente en una solicitud GET en el servidor.
  • Los componentes compuestos eliminan la necesidad de directivas 'use client' dentro del componente de servidor principal.
  • El uso de 'CompositeComponent' permite pasar componentes de cliente como 'slots' o hijos, delegando la responsabilidad de renderizado al código cliente.

El uso de componentes compuestos evita el desorden de mezclar límites servidor-cliente. Al tratar componentes de cliente como ranuras (slots), el componente de servidor no necesita conocer la implementación interna del componente cliente, mejorando la separación de responsabilidades y la experiencia de desarrollo.

Ranuras de datos y optimización de carga

  • Las 'render props' y 'component props' permiten inyectar datos del servidor directamente en componentes de cliente.
  • Es posible dividir la renderización de la página en múltiples funciones de servidor ejecutadas con 'Promise.all'.
  • El hook 'use' y 'Suspense' permiten cargar componentes de servidor de forma asíncrona mediante esqueletos en el cliente.

Para evitar solicitudes de datos duplicadas, el servidor puede pasar props directamente a componentes de cliente mediante funciones o componentes de marcador de posición. Además, la carga de componentes pesados se optimiza asíncronamente, permitiendo que la página renderice partes de forma independiente cuando la promesa correspondiente se resuelve.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video