Cómo me gusta escribir JavaScript

Rate this content
Bookmark

Me encanta escribir JavaScript. Se siente ligero, sin restricciones y flexible, todas cualidades que impulsan la creatividad y me invitan a practicar nuevas e interesantes técnicas. Con el tiempo, he desarrollado muchos patrones y principios que me ayudan en mi día a día. En esta charla, te mostraré algunos de ellos y luego veremos cómo los aplico dentro del propio código de AlpineJS. ¡Va a ser un buen momento!

26 min
05 Jun, 2023

Video Summary and Transcription

Caleb Porzio presenta Alpine JS, un framework de JavaScript, y demuestra el proceso de crear una versión rudimentaria de AlpineJS y refactorizarla. La charla cubre temas como la creación de un Dom Walker, la evaluación de expresiones, el uso de observadores de mutación y la refactorización del código. También se discuten técnicas como la inversión de condicionales, el uso de callbacks y el currying de parámetros. La charla enfatiza la importancia de la abstracción, la extracción de manejadores y un enfoque declarativo en el desarrollo de software.

Available in English

1. Introducción a Alpine JS

Short description:

Hola, mi nombre es Caleb Porzio. He creado un framework de JavaScript llamado Alpine JS. Vamos a crear una versión sencilla de AlpineJS, hacer un desastre y luego refactorizarlo utilizando técnicas de Alpine.

Hola, mi nombre es Caleb Porzio. He creado un framework de JavaScript llamado Alpine JS. Y cuando comencé con AlpineJS, no era un desarrollador de JavaScript experto, pero han pasado algunos años. He reescrito la base de código varias veces y ahora tengo muchas opiniones que creo que me ayudan a crear bases de código más mantenibles en las que realmente quiero trabajar.

Así que hoy vamos a crear esta pequeña versión sencilla de AlpineJS y básicamente vamos a hacer un desastre en el proceso, luego lo corregiremos y lo refactorizaremos utilizando algunas de las técnicas que he utilizado en Alpine. Así que vamos a hacerlo.

2. Creando el Dom Walker y Manejando Flame Click

Short description:

Aquí hay un botón en una página con una etiqueta de script vacía. Vamos a crear un pequeño espacio de juego. En lugar de usar el clic de exón de Alpine, usaremos el clic de llama y escribiremos JavaScript dentro de él. Creemos un script de Dom Walker para buscar atributos de clic de llama e inicializarlos. Comprobaremos si un elemento tiene el atributo de clic de llama y obtendremos su contenido.

Aquí hay un botón en una página con una etiqueta de script vacía. Este será nuestro pequeño espacio de juego. Y el framework que vamos a escribir es, no sé si has visto Alpine, pero con Alpine, puedes agregar cosas como escuchadores de clic directamente a los botones agregando atributos directamente en el HTML, como clic de exón. Bueno, en lugar de eso, vamos a hacer clic de llama y luego podemos escribir cualquier JavaScript aquí dentro. Así que escribamos algo como muy caliente.

De acuerdo. Y ahora, si cargamos esto en el navegador, no va a pasar nada. Tenemos este botón con clic de alerta. Muy caliente, lo hacemos clic y no pasa nada porque no hemos escrito ningún JavaScript para él. Así que hagámoslo. Lo primero que haría es crear un pequeño Dom Walker, un pequeño script que recorrerá cada elemento de la página y nos dará la oportunidad de buscar cosas como clic de llama e inicializarlas realmente. Así que escribamos un Dom Walker. Y con la magia de los fragmentos, no tienes que sentarte aquí y verme escribir un pequeño Dom Walker. Aquí está el script del Walker. Y este es el punto donde tenemos esta pequeña variable llamada L. Que en cada iteración de este bucle while simplemente recorrerá el siguiente nodo. Así que solo imprimamos L en la consola, actualicemos la página y asegurémonos de que funcione. Si miramos la consola, aquí está. Tenemos el botón, haz clic en mí. Ahora tenemos tres botones en la página. Actualicemos, hagamos que sean tres. Y recorrerá los tres. Si tuviéramos un botón anidado dentro de un div, también recorrería ese div. Y luego el botón dentro de él. Bien, genial. Tenemos nuestro pequeño Dom Walker. Ahora en esta parte, podemos hacer cosas con cada elemento. Y en nuestro caso, queremos verificar la existencia de este atributo de clic de llama diremos si L tiene el atributo clic de llama, entonces dejemos que la expresión sea igual a L.getAttribute(clic de llama). Esto obtendrá el contenido de ese atributo. De acuerdo.

3. Evaluando Expresiones y Observadores de Mutación

Short description:

Y esta expresión, simplemente registremos esta expresión, para que podamos ver que funcionó. Queremos escuchar realmente un evento de clic y luego evaluarlo. Ahora casi hemos terminado. Solo vamos a agregar una complejidad del mundo real a este lío. Eso será un observador de mutación. En Alpine, en realidad puedes cambiar o eliminar estos atributos sin recargar la página y Alpine detectará esos cambios. Así que escribamos un código de observador de mutación que nos permita engancharnos para eliminar ese atributo. ¿Qué queremos hacer cuando se haya eliminado el atributo? Bueno, queremos eliminar el escuchador de eventos que acabamos de agregar arriba. Así que hagámoslo. Ahora tenemos agregar escuchador de eventos.

Y esta expresión, simplemente registremos esta expresión, para que podamos ver que funcionó. Aquí tenemos alerta tan caliente. Y ahora, si queremos evaluar esto, hay esta pequeña función sucia. No se supone que debas usarla, pero la estamos usando para esta charla llamada eval, donde en realidad evaluará una cadena como código JavaScript.

Entonces, si actualizamos, evalúa alerta, tan caliente, pero no queremos eso. Queremos escuchar realmente un evento de clic y luego evaluarlo. Así que hagámoslo. L.addEventListener('click'). Y ahora podemos poner una pequeña función aquí. Hagámoslo. Bien, actualicemos. Y ahora no se mostrará la alerta hasta que haga clic, genial. Eso funcionó, ahora casi hemos terminado.

Solo vamos a agregar una complejidad del mundo real a este lío. Y eso será un observador de mutación. Así que en JavaScript, en tu navegador, hay una API llamada observador de mutación que puedes usar para observar mutaciones en el HTML. En Alpine, en realidad puedes cambiar o eliminar estos atributos sin recargar la página y Alpine detectará esos cambios. Si quitas un escuchador de clic en Alpine, en realidad eliminará el escuchador de clic del botón donde acabo de quitar el escuchador de clic en DevTools y ahora hago clic y en realidad no lo eliminó. Así que escribamos un código de observador de mutación que nos permita engancharnos para eliminar ese atributo. Hagámoslo. Bien. Nuevamente, no voy a hacerte ver cómo escribo todo, pero creamos un observador de mutación y especificamos algunas cosas como un filtro de atributos y que solo estamos observando mutaciones de atributos, y luego simplemente mostramos una alerta de eliminado desde aquí, solo para mostrarte que, okay, hacemos clic y funciona. Y ahora, si voy y realmente elimino este atributo, nos hemos enganchado en ese momento y podemos ejecutar código cuando se haya eliminado el atributo. ¿Qué queremos hacer cuando se haya eliminado el atributo? Bueno, queremos eliminar el escuchador de eventos que acabamos de agregar arriba. Así que hagámoslo. removeEventListener. Y cuando estás eliminando escuchadores de eventos, obtienes el elemento, especificas el nombre del evento y luego necesitas una referencia a la función controladora real que era el escuchador de eventos en primer lugar. Así que necesitamos extraer esto. Digamos que let handler = eval(expression). Bien, ahora tenemos agregar escuchador de eventos.

4. Refactorización y Diseño del Código

Short description:

Y ahora podemos eliminar ese escuchador de eventos cuando se haya eliminado el atributo. Esto es todo lo que necesitamos para crear nuestro pequeño MVP, un pequeño framework de JavaScript. Así que comencemos a refactorizar y hablar sobre mis valores como programador. Lo primero que suelo hacer cuando voy a refactorizar una base de código es empezar desde el principio. Hay mucho ruido visual sobre el recorrido del árbol DOM que no es necesario para entender todo. Escribamos el código que queremos que exista: recorramos un elemento, como el cuerpo del documento, y un callback donde obtengamos el elemento actual mientras hacemos ese recorrido del DOM. Y esto es todo lo que necesitamos para leer el código.

Y ahora podemos eliminar ese escuchador de eventos cuando se haya eliminado el atributo. Muy bien. Haz clic tan caliente. Ahora, si entramos aquí y eliminamos este atributo, hacemos clic y ahora no podemos ver esa alerta porque se ha eliminado el escuchador de eventos.

Así que esto es genial. Esto es todo lo que necesitamos para crear nuestro pequeño MVP, un pequeño framework de JavaScript. Lo llamaremos hot JS. Sí, esto es un desastre. Este es todo el código que escribirías si solo quisieras hacer el trabajo. Así que el resto de esta charla será refactorizar este código a algo más sensato y mantenible. Porque en este momento, si quisiéramos agregar más directivas, como flame, click, sería como flame text o algo así. Tendríamos que duplicar todo. Y ahí, ya sabes, sería un completo desastre.

Así que comencemos a refactorizar y hablar sobre mis valores como programador. Estas son muchas de mis opiniones. Esta es como la guía de estilo de Caleb Horzio para escribir JavaScript, muchas de mis opiniones y cómo abordo la refactorización. Lo primero que suelo hacer cuando voy a refactorizar una base de código es empezar desde el principio. Porque muchas veces es intimidante. ¿Por dónde empiezas? Todo es un desastre. Y generalmente es como, simplemente recorro el código hasta encontrar la primera cosa imperfecta o la primera cosa que no me gusta y luego empiezo desde ahí. Así que si hacemos eso, no es difícil. De inmediato, digo, okay, hay mucho ruido visual sobre el recorrido del árbol DOM que no es necesario para entender todo. Podemos extraer eso fácilmente. Y tampoco me gusta que haya, uh, esta variable current aquí arriba y luego este elemento temporal, y luego hay más código de recorrido del árbol aquí abajo. Así que hay una extracción obvia que quiero hacer, y diseñemos por pensamiento deseoso. Esa es una pequeña cita de Adam Wathen, donde cuando vas a refactorizar, básicamente escribes el código que quieres que exista y luego lo haces realidad. Así que escribamos el código que queremos que exista. Sería genial simplemente decir recorramos un elemento, como el cuerpo del documento, la etiqueta body de esta página, y luego un callback donde obtengamos el elemento actual mientras hacemos ese recorrido del DOM. Y esto es todo lo que necesitamos para leer el código.

5. Extracting Code into a Function

Short description:

Si estamos escribiendo este código para su consumo, esto es todo lo que necesitamos. Así que tengo un archivo utils.js donde vamos a almacenar todas estas funciones. Creemos una función llamada walk que acepte el elemento raíz y un callback. Podemos extraer el código que rodea al callback en la función walk. Esta es una extracción básica donde extraemos el código en una función y aceptamos un callback. Tenemos walk L y todo debería funcionar bien. Ejecutemos esto y asegurémonos de que funcione. No se pueden leer las propiedades de undefined porque no estamos pasando el elemento al callback. Todo funciona muy bien. Sigamos hasta encontrar algo que no sea perfecto. Esto es perfecto. Esto es perfecto. Aquí hay una gran declaración if, if L tiene atributo.

Si estamos escribiendo este código para su consumo, esto es todo lo que necesitamos. Todo este material son detalles de implementación.

De acuerdo. Así que tengo un archivo utils.js donde vamos a almacenar todas estas funciones. Creemos una función. La llamaremos walk y aceptaremos el elemento raíz y luego el caminante real, al que simplemente llamaremos callback. Y luego podemos extraer todo este código aquí. La mitad superior de pop aquí, ejecutamos ese callback, que será todo este código que pasaremos. Así que coloquemos esto aquí arriba. De acuerdo. Y luego este fragmento inferior, lo colocaremos aquí dentro. De acuerdo. Entonces, nuevamente, esta es una extracción bastante básica donde simplemente extraes el código que rodea algo en una función y aceptas un callback para el interior de lo que ese código estaba envolviendo. Así que tenemos walk L y todo lo demás debería funcionar bastante bien. Uh, esta es la única parte que necesitamos cambiar aquí. Y también necesitaremos importarlo en nuestro archivo aquí. Y ejecutemos esto y asegurémonos de que funcione. No funcionó. No se pueden leer las propiedades de undefined tiene atributo. Porque no estamos pasando el elemento al callback aquí. Digamos que ambos archivos se actualicen. Y ahí lo tenemos. Todo funciona muy bien. Muy bien. Comencemos desde el principio hasta encontrar algo que no sea perfecto. Esto es perfecto. Esto es perfecto. De acuerdo. Aquí hay una gran declaración if, if L tiene atributo.

6. Invertir Condiciones y Usar Cláusulas de Guardia

Short description:

Cuando me encuentro con una gran condición, me gusta invertir la condición y retornar temprano usando cláusulas de guardia. Esto hace que el código sea más legible y evita la anidación excesiva.

Y cuando me encuentro con algo que no funciona, voy a Si L tiene atributo. Y cuando me encuentro con una declaración if como esta, hay algunas cosas que pasan por mi cabeza. En general, las condiciones añaden complejidad que necesitas almacenar en tu cabeza cuando estás leyendo tus propios programas, porque es como si todo este código solo funcionara cuando hay. Un atributo en el elemento llamado flame click. Así que necesito mantener ese conocimiento en mi cabeza de que todo este código, necesitamos estar dentro de esa condición, lo cual, ya sabes, a medida que lo lees, es como si se sumara a esa carga. Así que una pequeña cosa que me gusta, una pequeña técnica que me gusta, um, cuando tengo una, ya sabes, una gran condición es invertir la condición y retornar temprano. Así que en este caso, podemos decir si no L tiene atributo, entonces retornar. Y ahora podemos ejecutar básicamente el resto del código sabiendo que tenemos ese atributo, pero sin ese nivel adicional de indentación. Y en este escenario, no es la mejor refactorización, pero solo quiero mencionar que uso estas, se llaman cláusulas de guardia. Las uso todo el tiempo. Es como sacar los casos excepcionales en la parte superior para que puedas escribir el código en el camino feliz. Y si tienes como cuatro niveles de anidamiento y conviertes esos en cuatro cláusulas de guardia, eso es mucho más legible que varios, ya sabes, niveles de anidamiento en toda la función. Muy bien. Así que esa es una pequeña técnica.

7. Usar Callbacks y Evitar Valores Nulos

Short description:

En lugar de usar una declaración if, utiliza un callback para recibir un valor. Crea una función llamada getAttribute para extraer la expresión. Evita posibles valores nulos utilizando un callback receptor. Esto asegura que la expresión exista y evita errores. Continúa con la implementación del código.

Otra técnica que me gusta es, en lugar de usar una declaración if, utilizar un callback para recibir un valor. Así que vamos a extraer esta expresión L.getAttribute en una pequeña función llamada getAttribute. Donde pasamos el elemento. Y el nombre del atributo que queremos obtener, que es flame click. Bien. Y escribamos esa función y hablaremos mientras avanzamos. getAttribute(elemento, nombre). Bien. Y algo como esto, vamos a poner esto aquí y llamaremos a esto nombre. Y ahora lo primero que podrías pensar en hacer es simplemente retornar esta expresión. Y así tendrías algo como let expresion igual a algo, pero entonces vuelves a donde empezaste. Tienes que decir, si no hay expresión, eso es un valor nulo, eso es un valor potencialmente nulo. Y cuando estás trabajando con código, como sabes, los valores que pueden ser potencialmente nulos son mortales para tus programas porque es muy difícil de determinar los pocos casos o muchos casos donde son nulos y luego obtienes todos esos errores, como tratar de, ya sabes, tratar nulo como una función o llamar a una propiedad en nulo o lo que sea. Así que lo que preferiría hacer en este escenario es crear un callback receptor. Así que en lugar de establecer una variable llamada expresión, ¿qué tal si creamos este pequeño callback receptor donde obtenemos expresión como el primer parámetro? Ahora, todo lo que está dentro de aquí tiene acceso a expresión, pero siempre estamos garantizados de que la expresión existe. Si no existe, este callback simplemente no se ejecutará. Así que convirtamos esa función en una función receptora. Así que si no tiene el nombre que estamos buscando, retornamos temprano, de lo contrario, agreguemos este pequeño parámetro aquí, este receptor, de lo contrario, en lugar de retornarlo, recibamos ese valor. Muy bien. Asegurémonos de que esto funcione. No va a funcionar porque no importamos esto. Ahora actualicemos y todo funciona. Genial. Muy bien. Sigamos adelante.

8. Abstracción y Extracción de Controladores

Short description:

Creamos una función llamada cuando se elimina el atributo para manejar la abstracción del observador de mutaciones. Agregamos el atributo a la página y nos aseguramos de que funcione. El código ahora es más legible y ordenado. Extraemos la variable del controlador en una función separada llamada on.

Entonces tenemos nuestra función walk. Tenemos nuestro receptor getAttribute. Eso está bastante bien. Tenemos este addEventListener, y lo vamos a extraer en un minuto. Pero lo siguiente que veo realmente imperfecto es simplemente que hay una abstracción fácil aquí. Este observador de mutaciones, hay código arriba y hay código abajo. Así que se convierte en una abstracción de función realmente rápida. Así que hagámoslo. Vamos a crear una función llamada cuando se elimina el atributo. Y luego pasaremos el elemento, el nombre del atributo y luego un callback para ejecutar cuando se elimine ese atributo. Básicamente podemos tomar el código así, ejecutar el callback y luego el resto del código debajo de eso, podemos ponerlo debajo.

De acuerdo, perfecto. Ahora tenemos una función attribute is removed y podemos agregarla a la página aquí. Una función attribute is removed L y luego este flame click. De acuerdo. Y luego nuestro callback aquí. De acuerdo. Eso se ve bastante bien. Asegurémonos de que funcione. De acuerdo. Eso funciona. Y ahora si eliminamos este atributo, el clic ha sido eliminado. Muy bien. Esto ya es mucho más legible. Si solo lo miramos rápidamente, podemos ver que todo está mucho más ordenado. Hemos extraído muchas de estas funciones básicas, la última cosa imperfecta mientras avanzamos es que tenemos que establecer esta variable del controlador para poder agregarla como un event listener y luego eliminarla como un event listener más adelante. Y esto no es tan malo, pero imaginemos que hay como cien líneas de código entre aquí y aquí. Y simplemente no se siente bien tener esta variable temporal siendo referenciada en partes tan diferentes de la base de código y extraerla. Como si fuéramos a hacer una pequeña función, así que hagámoslo. Hagamos una pequeña función llamada on donde pasamos el elemento, el nombre del evento que deseas y luego el controlador, y hagámoslo.

9. Refactorizando el Event Listener

Short description:

Entonces digamos on L click y luego handler, ya sabes, está bien. Pero este remove event listener, ¿cómo podemos hacer que esta parte sea parte de esta abstracción? Una técnica que me gusta usar es devolver la eliminación del event listener como una función desde el controlador on. Esto permite un código más limpio y evita la necesidad de una variable temporal separada. Importemos on y continuemos con el proceso de refactorización.

Entonces digamos on L click y luego handler, ya sabes, está bien. De acuerdo. Pero este remove event listener, ¿cómo podemos hacer que esta parte sea parte de esta abstracción, este on event listener y técnica que me gusta usar cuando estás tratando de extraer algo de dos capas diferentes de anidamiento. Hasta ahora, solo hemos extraído cosas en un solo nivel de condicionales o funciones o lo que sea. Solo un solo nivel de indentación. Esto es algo que queremos extraer tanto aquí como aquí. Así que se vuelve un poco complicado, no podemos simplemente copiar y pegar cosas aquí. Una técnica que me gusta usar para funciones que hacen algo como esto on, en realidad agrega un event listener. A menudo hay un desmontaje o algún tipo de procedimiento de limpieza para ese procedimiento. Como toda acción tiene una reacción opuesta. Como esta acción, este add event listener. También está la eliminación de ese event listener que está relacionada con agregarlo. Y para mantener eso en esta función, podemos devolverlo como una función. Mira esto. Si tomamos esto, eliminar event listener y realmente duplicamos esto y decimos, eliminar event listener así, ahora podemos devolverlo desde este controlador on, y luego no necesitamos tener este controlador como una variable temporal separada, podemos ver let off on L click de L expresión, y luego aquí abajo podemos simplemente ejecutar off. Esto es algo que me encanta, y hay tantas veces donde esto es útil, a menudo, ya sabes, cuando estás registrando event listeners o agregando a algún tipo de pila, es posible que desees devolver algún método o función para eliminarlo de esa pila o de la caché o es solo un patrón realmente útil que realmente me gusta, devolver un procedimiento de limpieza desde una función que tiene un procedimiento de limpieza. Entonces, de acuerdo, genial. Estoy realmente contento con esto. Importemos on y asegurémonos de que todo funcione. De acuerdo. Esto es como el paso uno en la refactorización. Creo que hemos llegado a un punto donde esto se ve bastante bien, pero es realmente solo una versión más legible de lo que comenzamos, es la misma estructura. Estamos recorriendo el DOM. Estamos obteniendo un atributo. Estamos escuchando un clic. Y luego, cuando se elimina el atributo, quitamos ese clic. Todavía hay muchos cambios estructurales que podemos hacer. Así que sigamos avanzando en eso.

10. Using Context and Parameter Currying

Short description:

Las funciones get attribute y when attribute is removed tienen parámetros similares. Para reducir la duplicación y mejorar la legibilidad, podemos modificar get attribute para que devuelva una función llamada on remove. Esta nueva función aceptará un callback y llamará internamente a when attribute is removed utilizando el contexto de get attribute. Al utilizar el contexto, podemos crear una función que solo requiera el callback. Esta técnica, conocida como parameter currying, simplifica el código y hace uso del contexto. Alternativamente, podemos utilizar la función bind para lograr el mismo resultado.

De acuerdo. Entonces, lo primero que vamos a hacer es modificar get attribute y when attribute is removed, ya que básicamente tienen los mismos parámetros que se les envían. En este nivel de código, cuando estamos recorriendo el DOM y obteniendo atributos, siento que no necesitamos tener todo este conocimiento. No creo que necesitemos usar get attribute y when attribute is removed. Además, parece haber mucha duplicación. ¿Qué tal si en lugar de eso, get attribute nos devuelve una función llamada on remove que podemos utilizar en lugar de pasar todos estos parámetros? Creo que eso limpiaría mucho el código.

Entonces, hagamos eso dentro de get attribute. En lugar de solo recibir la expresión, vamos a recibir una función llamada on remove y simplemente aceptaremos un callback de esta manera. Luego, dentro de aquí, podemos llamar a when attribute is removed de esta forma. Aceptaría un callback y lo pasaríamos a when attribute is removed, ya que ya tenemos el elemento y el nombre. ¿Tiene sentido? Ya tenemos este contexto desde la llamada a get attribute, así que podemos crear una pequeña función que solo necesite el callback y llame a when attribute is removed. Ahora que tenemos on remove, podemos hacer esto. on remove. Y eso es mucho mejor. Podemos limpiarlo aún más y simplemente devolver esa función así. Creo que eso es mucho más limpio. Esta es una técnica que uso mucho, donde si tienes contexto, úsalo. En este caso, tenemos el contexto y lo estamos utilizando. Lo que estamos haciendo aquí se llama parameter currying, o algo así. No sé los términos técnicos, pero básicamente es cuando tomas una función y llenas previamente algunos parámetros para luego pasar esa nueva función que solo necesita un parámetro o lo que sea, no necesita todos los parámetros. Se llama currying. Hay varias formas de hacerlo en JavaScript. Esta es la más literal, pero podríamos haber hecho algo como esto. Let on remove = when attribute is removed.bind. Entonces puedes usar esta función de JavaScript llamada bind, donde pasas este contexto y luego llenas previamente los parámetros. En nuestro caso, L y nombre, y te devolverá una función que ya tiene estos parámetros llenos. Y luego puedes hacer algo como on remove. De acuerdo.

11. Refactorización hacia un Enfoque Declarativo

Short description:

Este código es muy imperativo. Vamos a cambiarlo estructuralmente a un enfoque más declarativo registrando directivas y utilizando un método de inicio. Crearemos un nuevo archivo llamado directives.js para almacenar todas las funciones relacionadas con las directivas. Esto sigue el principio de un solo archivo. En lugar de clases, utilizamos módulos en JavaScript.

Entonces, creo que eso es una mejora y podríamos llegar incluso a pegarlo directamente en línea, porque va a devolver su función. Pero siento que eso es un poco demasiado. Siento que eso es un paso más allá de lo que necesitamos hacer. Muy bien. Y para nuestra gran refactorización final, nuevamente, todo esto es simplemente una forma más agradable de escribir lo que habíamos escrito antes. Cambiemos estructuralmente esto ahora mismo, este código es muy imperativo. Es decir, es paso a paso, es como recorrer el árbol DOM en cada iteración, verificar un atributo, obtener ese atributo, registrar un escuchador. En términos de mantenibilidad, eso no siempre es lo más mantenible. Entonces, si piensas en qué código quiero mantener, si este es mi pequeño marco de trabajo, ¿cuál es el código que si necesitara agregar un nuevo atributo, como flame text, tendría que copiar todo esto, tal vez esto se volvería enorme? Y todo está dentro de este walker. Es como, ¿y si simplemente fuera a un mundo de fantasía y escribiera lo que quiero? Bueno, en lugar de llamarlo attributes, llamémoslo directive. ¿Qué pasa si digo directive? Y luego podría decir algo como flame click, y luego tomemos todo este callback aquí. De acuerdo. E incluso, como estos son todos parámetros individuales que se pasan. Preferiría convertir esto en un objeto de cosas que se pasan para que pueda elegir qué cosas quiero, como, oh, solo quiero el elemento. O solo quiero el on remove, o solo quiero la expresión. Sí, esto está diseñado por pensamiento ilusorio. Para mí, esta es una forma mucho mejor de hacerlo. Entonces registramos la directiva, declaramos las directivas de manera más declarativa al principio, y ahora dentro de este walker tenemos algún método como boot o algo así como boot element. Y luego esta función de directiva registra una directiva en una pila de directivas, y luego boot recorre todas esas directivas y las inicia. Así que escribamos eso, vamos a salir de nuestros utils ahora mismo. Y vamos a crear un nuevo archivo llamado directives.js. Esto es otra cosa que me gusta hacer. Lo llamo el principio de un solo archivo, cuando estás escribiendo funciones que pertenecen juntas, las colocas en un solo archivo. Entonces, cualquier cosa relacionada con las directivas va en un solo archivo. De esa manera siempre sabes dónde encontrarlo. Si estás acostumbrado a la programación orientada a objetos, como PHP o Python o Java o algo así, estás acostumbrado a escribir clases como esta. Bueno, realmente no uso clases en JavaScript. Más bien uso estos módulos, estos archivos, donde en lugar de métodos, tengo funciones.

12. Exportación e Inicio de Directivas

Short description:

Y si exporto la función, es una función pública. Si no lo hago, es solo una función privada utilizada dentro del archivo. Podemos agregar propiedades escribiendo variables en la parte superior. Exportemos la función 'call directive', donde pasamos el nombre de la directiva y un callback para la inicialización. Necesitamos almacenar las directivas en un array llamado 'directives' y agregar un objeto con el nombre y la función de inicialización. La función 'boot' iterará a través de las directivas y ejecutará el código para cada directiva, pasando el atributo, el elemento y la función de inicialización.

Y si exporto la función, es una función pública. Si no lo hago, es solo una función privada utilizada dentro del archivo. Y puedo agregar lo que equivale a propiedades simplemente escribiendo variables en la parte superior. Y entenderás a qué me refiero. Así que exportemos esta función 'call directive', donde pasamos el nombre de la directiva y luego un callback que maneja la inicialización. Podríamos llamarlo 'initialize' para que sea más legible o algo así.

De acuerdo. Y ahora aquí no tenemos los elementos actuales, así que tenemos que cambiar un poco la estructura. Necesitamos almacenar todas estas directivas para poder iniciarlas más tarde. Así que creemos una pequeña propiedad llamada 'directives' igual a. Y es solo un array. Y luego aquí diremos 'directives.push', y agreguemos un pequeño objeto con el nombre y luego esta función de inicialización. De acuerdo. Entonces, cuando se ejecute el código, cuando se ejecute esta directiva, simplemente las guardará para nosotros en esta variable, esta propiedad llamada 'directives' hasta que las usemos en 'boot'. Así que creemos esa función 'boot'. Muy bien. Y 'boot' acepta un elemento.

Y ahora 'boot' va a recorrer esas directivas. Entonces 'directives.forEach', y esto será una directiva, una individual. Y ahora esta directiva individual, podemos tomar este código que teníamos antes. Y ahora realmente lo ejecutaríamos así para esta directiva, obtendremos el atributo. Ya tenemos el elemento. Diremos 'directive.name'. Y en este caso, podríamos simplemente pasar 'directive.initialize', y tal vez hagamos eso solo por ahora para asegurarnos de que todo funcione, pero en realidad no vamos a hacer eso. En lugar de pasar 'initialize', vamos a pasar nuestro propio callback aquí. Y luego llamar a esta función de inicialización. Y recuerda, 'initialize' es lo que pasamos a la directiva y 'initialize' espera este objeto de parámetros. Así que simplemente peguemos eso aquí. De acuerdo. Tenemos el elemento, necesitamos la expresión.

13. Invertir el Flujo y Escribir Código Legible

Short description:

Recuerda, hemos invertido el flujo elevando las declaraciones y usando una función de inicio para el bucle. Hay muchas más optimizaciones y refactorizaciones que se pueden hacer, pero por ahora, mantengámoslo a este nivel. Esta estructura es cómo se escribe Alpine, lo que lo hace más legible. Espero que hayas aprendido algo sobre la refactorización de JavaScript en funciones con nombres adecuados.

Recuerda, 'get attribute' devuelve un atributo y lo devuelve en 'remove'. De acuerdo. Así que importemos eso desde nuestro nuevo 'directives.js' e importemos 'boot'. Y ahora esto, necesitamos importar 'get attribute' desde 'utils'. Y veamos si esto funciona. 'Initialize' no está definido. De acuerdo. Así que tenemos 'initialize', pero en realidad es una propiedad de nuestra directiva, esta directiva que pasamos. Así que 'directive.initialize'. Y ahí lo tenemos. Todo sigue funcionando. Y para mí, hemos invertido un poco el flujo aquí. En lugar de recorrer directamente algo y hacer algo o hacer un puñado de cosas en cada bucle, hemos elevado esas cosas que estamos haciendo en declaraciones en la parte superior. Y ahora, cuando hacemos el bucle real, es solo esta pequeña función de inicio que recorre esas cosas que declaramos. Así que espero que esto tenga sentido para ti. Sé que, ya sabes, tener que mirar esto, no pasa fácilmente la prueba de la vista rápida. Pero sé que mirar esto puede ser un poco abrumador. Pero creo que entiendes la idea. Pero creo que entiendes la idea. Así que hay muchas más optimizaciones que podríamos hacer en este método. Podríamos proporcionar directamente aquí y completar parte de este contexto, como hicimos antes con el 'currying'. Hay tanto más que podríamos hacer. Hay tantas más refactorizaciones que me gustaría hacer, pero vamos a mantenerlo a este nivel por ahora. Y espero que esto te haya dado un poco de perspectiva sobre cómo me gusta escribir cosas y cómo me gusta estructurar el código y solo para que lo sepas, esto es muy similar a cómo se escribe Alpine en realidad. Hay un archivo en el núcleo de Alpine llamado 'directives' que tiene una función llamada 'directive' que almacena todos los controladores en este objeto y luego puedes inicializarlos más tarde. Todo lo que te he mostrado es básicamente cómo se escribe el núcleo de Alpine en sí mismo, lo que creo que lo hace mucho más legible y sí. Así que espero que hayas recogido uno o dos consejos sobre la refactorización de JavaScript en funciones con nombres adecuados. Sí. Gracias. Nos vemos.

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 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!
Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Top Content
Do you have a large product built by many teams? Are you struggling to release often? Did your frontend turn into a massive unmaintainable monolith? If, like me, you’ve answered yes to any of those questions, this talk is for you! I’ll show you exactly how you can build a micro frontend architecture with Remix to solve those challenges.
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 Summit 2023React Summit 2023
32 min
Speeding Up Your React App With Less JavaScript
Top Content
Too much JavaScript is getting you down? New frameworks promising no JavaScript look interesting, but you have an existing React application to maintain. What if Qwik React is your answer for faster applications startup and better user experience? Qwik React allows you to easily turn your React application into a collection of islands, which can be SSRed and delayed hydrated, and in some instances, hydration skipped altogether. And all of this in an incremental way without a rewrite.
JSNation 2022JSNation 2022
28 min
Full Stack Documentation
Top Content
Interactive web-based tutorials have become a staple of front end frameworks, and it's easy to see why — developers love being able to try out new tools without the hassle of installing packages or cloning repos.But in the age of full stack meta-frameworks like Next, Remix and SvelteKit, these tutorials only go so far. In this talk, we'll look at how we on the Svelte team are using cutting edge web technology to rethink how we teach each other the tools of our trade.
GraphQL Galaxy 2021GraphQL Galaxy 2021
32 min
From GraphQL Zero to GraphQL Hero with RedwoodJS
Top Content
We all love GraphQL, but it can be daunting to get a server up and running and keep your code organized, maintainable, and testable over the long term. No more! Come watch as I go from an empty directory to a fully fledged GraphQL API in minutes flat. Plus, see how easy it is to use and create directives to clean up your code even more. You're gonna love GraphQL even more once you make things Redwood Easy!

Workshops on related topic

JSNation 2023JSNation 2023
170 min
Building WebApps That Light Up the Internet with QwikCity
Featured WorkshopFree
Building instant-on web applications at scale have been elusive. Real-world sites need tracking, analytics, and complex user interfaces and interactions. We always start with the best intentions but end up with a less-than-ideal site.
QwikCity is a new meta-framework that allows you to build large-scale applications with constant startup-up performance. We will look at how to build a QwikCity application and what makes it unique. The workshop will show you how to set up a QwikCitp project. How routing works with layout. The demo application will fetch data and present it to the user in an editable form. And finally, how one can use authentication. All of the basic parts for any large-scale applications.
Along the way, we will also look at what makes Qwik unique, and how resumability enables constant startup performance no matter the application complexity.
React Summit 2023React Summit 2023
106 min
Back to the Roots With Remix
Featured Workshop
The modern web would be different without rich client-side applications supported by powerful frameworks: React, Angular, Vue, Lit, and many others. These frameworks rely on client-side JavaScript, which is their core. However, there are other approaches to rendering. One of them (quite old, by the way) is server-side rendering entirely without JavaScript. Let's find out if this is a good idea and how Remix can help us with it?
Prerequisites- Good understanding of JavaScript or TypeScript- It would help to have experience with React, Redux, Node.js and writing FrontEnd and BackEnd applications- Preinstall Node.js, npm- We prefer to use VSCode, but also cloud IDEs such as codesandbox (other IDEs are also ok)
React Day Berlin 2022React Day Berlin 2022
86 min
Using CodeMirror to Build a JavaScript Editor with Linting and AutoComplete
Top Content
WorkshopFree
Using a library might seem easy at first glance, but how do you choose the right library? How do you upgrade an existing one? And how do you wade through the documentation to find what you want?
In this workshop, we’ll discuss all these finer points while going through a general example of building a code editor using CodeMirror in React. All while sharing some of the nuances our team learned about using this library and some problems we encountered.
TestJS Summit - January, 2021TestJS Summit - January, 2021
173 min
Testing Web Applications Using Cypress
WorkshopFree
This workshop will teach you the basics of writing useful end-to-end tests using Cypress Test Runner.
We will cover writing tests, covering every application feature, structuring tests, intercepting network requests, and setting up the backend data.
Anyone who knows JavaScript programming language and has NPM installed would be able to follow along.
Node Congress 2023Node Congress 2023
63 min
0 to Auth in an Hour Using NodeJS SDK
WorkshopFree
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool.
We will enhance a full-stack JS application (Node.JS backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:- User authentication - Managing user interactions, returning session / refresh JWTs- Session management and validation - Storing the session for subsequent client requests, validating / refreshing sessions
At the end of the workshop, we will also touch on another approach to code authentication using frontend Descope Flows (drag-and-drop workflows), while keeping only session validation in the backend. With this, we will also show how easy it is to enable biometrics and other passwordless authentication methods.
Table of contents- A quick intro to core authentication concepts- Coding- Why passwordless matters
Prerequisites- IDE for your choice- Node 18 or higher
React Summit US 2023React Summit US 2023
96 min
Build a powerful DataGrid in few hours with Ag Grid
WorkshopFree
Does your React app need to efficiently display lots (and lots) of data in a grid? Do your users want to be able to search, sort, filter, and edit data? AG Grid is the best JavaScript grid in the world and is packed with features, highly performant, and extensible. In this workshop, you’ll learn how to get started with AG Grid, how we can enable sorting and filtering of data in the grid, cell rendering, and more. You will walk away from this free 3-hour workshop equipped with the knowledge for implementing AG Grid into your React application.
We all know that rolling our own grid solution is not easy, and let's be honest, is not something that we should be working on. We are focused on building a product and driving forward innovation. In this workshop, you'll see just how easy it is to get started with AG Grid.
Prerequisites: Basic React and JavaScript
Workshop level: Beginner