Video Summary and Transcription
La charla de hoy presenta React Snots, una nueva forma de composición para sistemas de diseño. La forma de configuración proporciona flexibilidad pero puede llevar a casos de uso no controlados y patrones incorrectos. Se creó React Slots RFC para abordar las limitaciones del soporte de React para componentes web y slots. Introduce las APIs createHost y createSlot para habilitar la composición de componentes y resolver problemas anteriores. React Slots RFC permite un estilo de componente flexible y la creación de estructuras complejas sin renderizarlas en el navegador.
1. Introducción a React Snots y Diseño de API
Hoy, mi tema es React Snots, una nueva forma de composición. Cada vez que encontraba un nuevo sistema de diseño, lo primero que hacía era ver cómo implementaban el componente de entrada de texto. La solución es simple. Podemos pasar el nombre de la clase y el estilo al contenedor del componente en su lugar. Similar a WrapRef, podemos introducir indicaciones de contenedor, indicaciones de etiqueta e indicaciones de descripción. Aquí está la API de entrada de texto de man time.
Hey, es un gran honor estar aquí para compartir con ustedes algunos de mis pensamientos sobre el sistema de diseño. Mi nombre es Gongwu Nie, pueden llamarme Neo. Hoy, mi tema es React Snots, una nueva forma de composición.
Antes de sumergirnos en el tema, me gustaría contar la historia primero. Cuando trabajo en el sistema de diseño, siempre estoy pensando, ¿cómo construir componentes flexibles y a prueba de futuro? Para mí, lo más difícil no es crear nuevos componentes o solucionar errores extraños. Es el diseño de la API del componente diseño.
Cada vez que encontraba un nuevo sistema de diseño, lo primero que hacía era ver cómo implementaban el componente de entrada de texto, porque es uno de los componentes más misteriosos. Permítanme mostrarles. La entrada de texto es simple y directa. Viene con una etiqueta, una entrada y tiene una prueba. Primero añadamos soporte para accessibility. Al construir un componente compartible, por favor no olviden reenviar ref. Necesitamos la ref al input para enfocarlo en form validation. ¿Pero qué pasa con el contenedor? También necesitamos la ref al contenedor para adjuntarle propover o tooltip en algunos casos. Bueno, podemos añadir un contenedor para ello.
Pero espera, ¿has notado un problema potencial con el enfoque actual? ¿Qué sucederá si intentamos añadir algunos márgenes al componente desde el otro componente? Aumentará el margen entre la etiqueta, la entrada y la descripción en su lugar, porque extendemos todos los demás indicadores al elemento de entrada interno. La solución es simple. Podemos pasar el nombre de la clase y el estilo al contenedor del componente en su lugar. ¿Se ve bien? El problema es que el componente se está volviendo confuso para los consumidores. ¿Qué indicación se pasará al contenedor? ¿Qué indicación se pasará a la entrada? El componente se convierte en una caja negra. En realidad, el equipo de producto seguirá pidiendo más opciones para acceder a los elementos internos, como adjuntar eventos de punto o añadir atributos de data a la etiqueta o descripción. Similar a WrapRef, podemos introducir indicaciones de contenedor, indicaciones de etiqueta e indicaciones de descripción. Funciona. Pero no termina aquí. ¿Qué pasa si necesitamos añadir alrededores a la entrada, más indicaciones. Ahora puedes ver cómo la API se hincha con este enfoque. Aquí está la API de entrada de texto de man time. No me malinterpreten. Man time es una gran biblioteca de componentes. Me encanta mucho.
2. Forma de Configuración y Composición de Componentes
Eligen la forma de configuración para diseñar la API del componente. En la forma de configuración, tenemos que soportar la flexibilidad con la inflación de la API, y los componentes se convierten en una caja negra completa para los consumidores. Retrocedamos un paso y pensemos, ¿cómo construimos nuestra aplicación web en React? Componemos componentes. Cada componente simplemente hace su propio trabajo y eso es todo. Simple y flexible.
Eligen la forma de configuración para diseñar la API del componente. En la forma de configuración, tenemos que soportar la flexibilidad con la inflación de la API, y los componentes se convierten en una caja negra completa para los consumidores.
Retrocedamos un paso y pensemos, ¿cómo construimos nuestra aplicación web en React? Componemos componentes. Cada componente simplemente hace su propio trabajo y eso es todo. Simple y flexible.
Entonces, ¿qué pasaría si usamos el mismo enfoque para los componentes compartibles? Ganamos la misma claridad, simplicidad y flexibilidad. Muchas bibliotecas de componentes populares están utilizando la CompositionWay para implementar componentes accesibles como Chakra UI, Redux primitives, Hedonist UI, y más.
Para soportar la accesibilidad, tenemos que usar el Contexto de React para comunicarnos entre el padre y los hijos para coordinar los atributos de accesibilidad. La configuración es simple de usar. Realmente quieres escribir tu módulo en el estilo de la izquierda en lugar del estilo de la derecha. Pero la CompositionWay no es la respuesta final.
3. Consistencia y Flexibilidad de Componentes
Tomemos Chakra UI como ejemplo. ¿Qué pasaría si intercambiamos la posición de inputLeftAddon e inputRightAddon? Obtendríamos inputLeftAddon mostrado en el lado derecho e inputRightAddon mostrado en el lado izquierdo. Al construir una Lista Accesible, los padres necesitan conocer la información de los hijos para que sea compatible con la accesibilidad. La forma de configuración proporciona la mejor consistencia, ya que el componente es una única fuente de verdad. La forma de composición proporciona la mejor flexibilidad, pero conduce a casos de uso no controlados y patrones incorrectos. Slots es el estándar para los componentes web, permitiéndote definir marcadores de posición que pueden ser llenados con cualquier fragmento de marcado que desees.
Tomemos Chakra UI como ejemplo. ¿Qué pasaría si intercambiamos la posición de inputLeftAddon e inputRightAddon? Obtendríamos inputLeftAddon mostrado en el lado derecho e inputRightAddon mostrado en el lado izquierdo. Esto rompe la semántica con un estilo roto. Tengo un hobby cuando encuentro un nuevo sistema de design es testing la resonancia de los componentes. Al agregar nodos extra a los elementos, vemos cómo se rompen. Para un sistema de design dedicado, entregamos componentes bien diseñados. Pero simplemente no puedes imaginar cómo los desarrolladores alternativos los romperán de diversas maneras, y desafortunadamente, no podemos evitar que lo hagan.
Dirías, no importa si seguimos el orden de design correctamente. OK, veamos otro problema más realista. Al construir una Lista Accesible, los padres necesitan conocer la información de los hijos para hacer que sea compatible con la accessibility para Azure Active Descendant es fácil de lograr usando la forma de configuración porque el padre conoce todos los elementos del ItemPrompt. Pero es un poco engorroso para la forma de composición. El menú no puede ver sus elementos internos. El componente está ciego. Para resolver el problema, podemos usar react-children con react-clone-element. Entonces podemos tomar el control de la renderización de los elementos en el componente padre. Pero en términos de extensión, se romperá de nuevo. Incluso podemos iterar los hijos, el padre sigue estando ciego ya que no puede ver los detalles profundos. El problema está bien descrito por root UI, si estás interesado, aquí tengo una tarea para que descubras cómo esas bibliotecas están tratando de resolver este problema.
Recapitulemos, la forma de configuración proporciona la mejor consistencia, ya que el componente es la única fuente de verdad, pero es difícil de extender, y se convierte en una caja negra cuando se utilizan múltiples elementos. Por el contrario, la forma de composición proporciona la mejor flexibilidad, puedes personalizar tus sub-componentes libremente, pero causa otro problema, la consistencia, conduce a casos de uso no controlados y patrones incorrectos. Entonces, ¿podemos tener una forma de construir componentes con flexibilidad mientras mantenemos la consistencia? Sí, la respuesta es no. Slots es el estándar para los componentes web. En los componentes web, los slots son identificados por su atributo de nombre y te permiten definir marcadores de posición en tus plantillas que pueden ser llenados con cualquier fragmento de marcado que quieras cuando el elemento se usa en el marcado. Es más fácil entender el concepto en code. Primero, definimos una plantilla con algunos marcadores de posición nombrados y definimos el componente web. Luego llenamos los marcadores de posición nombrados con slots nombrados. Finalmente, obtenemos el resultado con elementos inyectados. Aquí puedes ver cómo se garantiza la consistencia. El diseño está definido en la plantilla, no descrito por el orden de composición. Algunos frameworks populares como Vue y Svelte también implementaron el patrón de composición de slots desde el nivel de framework en un comportamiento similar.
4. React Slots RFC y los Desafíos
React no soporta bien los componentes web y los slots. Se han intentado varios enfoques, como el uso de react-children con react-clone-element, pero tienen limitaciones. React Spectrum utiliza el contexto y el orden de la cuadrícula, pero tiene una funcionalidad limitada. GitHub Primer utiliza una doble renderización, pero no soporta la renderización en el lado del servidor. Un paquete experimental llamado React-core-return fue prometedor pero fue eliminado. Por lo tanto, se creó React Slots RFC para abordar estos problemas.
Pero como sabes, React todavía no soporta muy bien los web components, sin hablar de los slots. Hay muchos enfoques de la community intentando traer los slots al mundo de React. La forma más común es usando react-children con react-clone-element. Pero no scale muy bien ya que el componente está ciego. React Spectrum utiliza el contexto y el orden de la cuadrícula para resolver el problema del desorden, pero la funcionalidad es limitada. Por ejemplo, con el orden de la cuadrícula, cambiamos el índice de tipo de una manera inesperada. GitHub Primer utiliza una doble renderización para acercarse a los slots. Renderiza los subcomponentes en un navegador con contenido vacío y recopila la información del slot primero, y luego utiliza el slot en la segunda renderización. El problema es obvio. No soporta la renderización en el lado del servidor. Hubo un paquete experimental del equipo central de React llamado React-core-return, que proporciona una forma de interpolar los hijos durante la fase de renderización. Podría ser el mejor candidato para traer los slots a React, pero desafortunadamente, fue eliminado poco después. Así que creé React Slots RFC para esbozar los problemas con la propuesta. Permíteme mostrarte el code directamente.
5. React Slots RFC y la Composición de Componentes
De nuevo, el típico componente de entrada de texto implementado en React Slots RFC. Introdujimos dos nuevas APIs llamadas createHost y createSlot, similares a React call return pero con un modelo mental más sencillo. El createHost crea la plantilla y el createSlot crea los marcadores de posición, permitiéndonos interactuar con los elementos. Esto abre nuevas posibilidades para la composición de componentes y proporciona una solución a los problemas anteriores. Ahora podemos demostrar cómo React Slots RFC resuelve estos problemas y soporta la accesibilidad, la flexibilidad y la resistencia de los componentes.
De nuevo, el típico componente de entrada de texto implementado en React Slots RFC. En el RFC, introdujimos dos nuevas APIs llamadas createHost y createSlot, que es muy similar a React call return pero con un modelo mental mucho más sencillo. El createHost crea la plantilla y el createSlot crea los marcadores de posición, y luego compone el Slot en el componente host. Es bastante similar a Slot para web components, pero mucho más poderoso, ya que no simplemente inyectamos los elementos, los interactuamos.
Abre el tercer ojo del componente, ahora el padre puede ver los detalles profundos de sus hijos, no importa cómo se haya extendido. Ahora, tiempo de demostración. Te mostraré cómo los problemas anteriores serán perfectamente resueltos por React Slots RFC. Aquí, implementé el React Slots RFC con react-core-return en 10 líneas. Y luego, el campo de texto, primero, creamos los slots para la etiqueta, la entrada y la etiqueta. Pasamos los hijos a createHost, luego nos da los slots. Aquí puedes ver cómo podemos interpolar los slots. Eso significa que podemos hacer todo lo que queramos en un solo lugar. Aquí puedes ver cómo soporto la accessibility para la entrada de texto. Podemos leer el ID de entrada directamente para la etiqueta, y también podemos iterar todo el texto.
Ahora, te mostraré algo de magia. No importa cómo componga los slots, no cambia el resultado porque el diseño está definido en la plantilla por createHost. Mientras tanto, todavía somos libres de extender los slots. Por ejemplo, extendemos la etiqueta, extendemos la entrada, y podemos cambiar el orden de la etiqueta. Cambiará el resultado porque es una lista. Y el otro problema es la resistencia del componente. Déjame intentar envolver la etiqueta con un nodo extra. Funcionará porque no es un nodo. Eso es muy importante para un sistema de design dedicado, porque hemos preparado un muy... Hemos preparado los componentes. No deberíamos cambiar el diseño fácilmente. Volvamos a cambiarlo. Otro caso de uso es que lo que sea que usemos, no está fuera del host. No se renderizará nada. Eso también es importante para un sistema de design consistente. Los slots anidados también son soportados.
6. React Slots RFC y la Flexibilidad de Componentos
React Slots RFC nos permite crear entradas de texto sin la necesidad de etiquetas o entradas estilizadas. En su lugar, las estilizamos en la plantilla. El slot actúa como un portador de datos, permitiéndonos crear estructuras complejas como árboles sin renderizarlas en el navegador. Aún podemos acceder a los datos y beneficiarnos de las características de React, como los métodos de ciclo de vida y el contexto.
¿Has notado cómo creamos las entradas de texto, no necesitamos crear una etiqueta de campo de texto estilizada o una entrada de campo de texto. En su lugar, lo estilizamos en la plantilla. El slot en sí no renderiza nada, solo es un portador de data. Eso significa mucho. Por ejemplo, podemos crear un constructor de árboles. Aquí está el ejemplo. Creamos un árbol, pero no se renderiza nada en el navegador. Pero puedes ver en el console log. Aquí está el árbol, el menú anidado, pero aquí es cómo los componemos. Pero no se renderiza en el navegador en absoluto. Pero aún así, podemos obtener data, porque el slot es solo un portador de data. No es necesario que se renderice en el navegador en absoluto. Y puedes ver cómo es reactivo. O eliminar el menú anidado. Así que aún podemos beneficiarnos de todo lo que React nos proporciona. Los ciclos de vida, las estancias, el contexto, todas las demás cosas. Hay un paquete llamado React New. Intentando hacer lo mismo pero veamos el tamaño. Son casi 100 KB minimizados, incluso 30 KB minimizados, y CCPT haciendo lo mismo porque tiene que incluir el reconciliador de React en él. Pero con React-SNOS podemos usar el reconciliador de React directamente. Ahora puedes ver cómo logramos la flexibilidad manteniendo la consistencia en React-SNOS-RFC con un modelo de personalización descentralizada y control centralizado. ¿Qué significa esto para nosotros? Ahora, el componente host es la única fuente de verdad y toma el control de sus hijos, como la forma de configuración. Así que podemos hacer que el componente Composable sea predecible. Puedes ver lo sencillo que es añadir soporte para accessibility. Y porque no es necesario renderizar los slots en un árbol DOM, en su lugar simplemente conectamos la información y luego decidimos qué renderizar basándonos en la información conectada. Así que, el soporte de virtualización está fuera de la caja y más posibilidades, por ejemplo, el renderizador de clientes. Además, creé un paquete llamado create-slots que implementa completamente el RFC de react-slots, a diferencia de otros enfoques, que no funcionan bien con algunas características de react como el renderizado del lado del servidor. Utilicé la pre-renderización que es similar a react-call-return para recoger la información de los hijos durante la fase de renderizado y usar la información más tarde durante la misma fase de renderizado, y luego podemos comprometer el resultado interpolado en el navegador. Y ya se ha utilizado en el sistema de design de Revolut. Como también estamos utilizando la forma de composición para construir nuestros componentes compartidos, tenemos casi 200 componentes compartidos y enfrentamos más problemas de los que he discutido aquí y eso finalmente me llevó a esta masterclass. Pero el paquete no es ideal, ya que repite el trabajo del Reconciliador de React. Por eso todavía quiero ver el apoyo de React en sí mismo. Y eso es todo. Si quieres discutir más, puedes encontrarme en GitHub y Twitter. Gracias.
Comments