Características principales del framework
Cada uno de los principales frameworks de JavaScript tiene un enfoque
diferente para actualizar el DOM, gestionar eventos del navegador y
proporcionar una experiencia agradable para el desarrollador. En este artículo,
se explorarán las características principales de los "cuatro grandes"
frameworks, observando cómo suelen funcionar desde un nivel superior y las
diferencias entre ellos.
Prerrequisitos: Familiaridad con los lenguajes básicos HTML , CSS y JavaScript .
Resultados del Comprenda las características principales que ofrecen los frameworks de
aprendizaje: JavaScript.
Lenguajes específicos de dominio
La mayoría de los frameworks permiten utilizar lenguajes específicos de
dominio (DSL) para crear aplicaciones. En particular, React ha popularizado el
uso de JSX para escribir sus componentes, mientras que Ember
utiliza Handlebars . A diferencia de HTML, estos lenguajes saben leer variables
de datos, y estos datos se pueden utilizar para agilizar el proceso de escritura
de la interfaz de usuario.
Las aplicaciones Angular suelen hacer un uso intensivo de TypeScript .
TypeScript no se ocupa de la escritura de interfaces de usuario, pero es un
lenguaje específico de dominio y tiene diferencias significativas con respecto
a JavaScript.
Los DSL no pueden ser leídos por el navegador directamente; primero deben
ser transformados a JavaScript o HTML. Las herramientas del framework
generalmente incluyen las herramientas necesarias para manejar este paso, o
pueden ser ajustadas para incluir este paso. Si bien es posible crear
aplicaciones de framework sin usar estos lenguajes específicos del dominio,
adoptarlos agilizará su proceso de desarrollo y facilitará la búsqueda de ayuda
de las comunidades relacionadas con esos frameworks.
JSX
JSX , que significa JavaScript y XML, es una extensión de JavaScript que
incorpora una sintaxis similar a la de HTML a un entorno JavaScript. Fue
inventado por el equipo de React para su uso en aplicaciones React, pero se
puede utilizar para desarrollar otras aplicaciones, como las aplicaciones Vue,
por ejemplo.
A continuación se muestra un ejemplo simple de JSX:
jsxCopiar al portapapeles
const subject = "World";
const header = (
<header>
<h1>Hello, {subject}!</h1>
</header>
);
Esta expresión representa un <header>elemento HTML con un <h1>elemento
dentro. Las llaves que lo rodean {subject}indican a la aplicación que lea el
valor de la subjectconstante y lo inserte en nuestro <h1>.
Cuando se usa con React, el JSX del fragmento anterior se compilará en esto:
jsCopiar al portapapeles
const subject = "World";
const header = React.createElement(
"header",
null,
React.createElement("h1", null, "Hello, ", subject, "!"),
);
Cuando el navegador lo procese finalmente, el fragmento anterior producirá
un código HTML que se verá así:
htmlCopiar al portapapeles
<header>
<h1>Hello, World!</h1>
</header>
Bigote daliniano
El lenguaje de plantillas Handlebars no es específico de las aplicaciones
Ember, pero se utiliza mucho en ellas. El código Handlebars se parece al
HTML, pero tiene la opción de extraer datos de otro lugar. Estos datos se
pueden utilizar para influir en el HTML que finalmente crea una aplicación.
Al igual que JSX, Handlebars utiliza llaves para introducir el valor de una
variable. Handlebars utiliza un par doble de llaves, en lugar de un par único.
Dada esta plantilla de manillar:
htmlCopiar al portapapeles
<header>
<h1>Hello, {{subject}}!</h1>
</header>
Y estos datos:
jsCopiar al portapapeles
{
subject: "World";
}
Handlebars creará HTML de la siguiente manera:
htmlCopiar al portapapeles
<header>
<h1>Hello, World!</h1>
</header>
Mecanografiado
TypeScript es un superconjunto de JavaScript, lo que significa que extiende
JavaScript: todo el código JavaScript es TypeScript válido, pero no al revés.
TypeScript es útil por la rigurosidad que permite a los desarrolladores
imponer en su código. Por ejemplo, considere una función add()que toma
números enteros ay bdevuelve su suma.
En JavaScript, esa función podría escribirse así:
jsCopiar al portapapeles
function add(a, b) {
return a + b;
}
Este código puede resultar trivial para alguien acostumbrado a JavaScript,
pero aún así podría ser más claro. JavaScript nos permite usar el +operador
para concatenar cadenas, por lo que esta función técnicamente seguiría
funcionando si ay bfueran cadenas, pero es posible que no te dé el resultado
que esperas. ¿Qué sucede si solo queremos permitir que se pasen números a
esta función? TypeScript lo hace posible:
losCopiar al portapapeles
function add(a: number, b: number) {
return a + b;
}
El : numbertexto escrito después de cada parámetro aquí le dice a TypeScript
que tanto acomo bdeben ser números. Si usáramos esta función y '2'la
pasáramos como argumento, TypeScript generaría un error durante la
compilación y nos veríamos obligados a corregir nuestro error. Podríamos
escribir nuestro propio JavaScript que genere estos errores por nosotros,
pero haría que nuestro código fuente fuera significativamente más detallado.
Probablemente tenga más sentido dejar que TypeScript se encargue de
dichas comprobaciones por nosotros.
Componentes de escritura
Como se mencionó en la lección anterior, la mayoría de los frameworks
tienen algún tipo de modelo de componentes. Los componentes de React se
pueden escribir con JSX, los componentes de Ember con Handlebars y los
componentes de Angular y Vue con una sintaxis de plantillas que extiende
ligeramente HTML.
Independientemente de sus opiniones sobre cómo se deben escribir los
componentes, los componentes de cada marco ofrecen una forma de
describir las propiedades externas que pueden necesitar, el estado interno
que el componente debe gestionar y los eventos que un usuario puede
activar en el marcado del componente.
Los fragmentos de código en el resto de esta sección utilizarán React como
ejemplo y están escritos con JSX.
Propiedades
Las propiedades, o props , son datos externos que necesita un componente
para poder renderizarse. Supongamos que está creando un sitio web para
una revista en línea y necesita asegurarse de que cada escritor colaborador
reciba el crédito por su trabajo. Puede crear un AuthorCreditcomponente
para acompañar cada artículo. Este componente debe mostrar un retrato del
autor y una breve firma sobre él. Para saber qué imagen renderizar y qué
firma imprimir, AuthorCreditdebe aceptar algunas propiedades.
Una representación React de este AuthorCreditcomponente podría verse así:
jsxCopiar al portapapeles
function AuthorCredit(props) {
return (
<figure>
<img src={props.src} alt={props.alt} />
<figcaption>{props.byline}</figcaption>
</figure>
);
}
{props.src}, {props.alt}, y {props.byline}representan dónde se insertarán
nuestras propiedades en el componente. Para representar este componente,
escribiríamos un código como este en el lugar donde queremos que se
represente (que probablemente será dentro de otro componente):
jsxCopiar al portapapeles
<AuthorCredit
src="./assets/zelda.png"
alt="Portrait of Zelda Schiff"
byline="Zelda Schiff is editor-in-chief of the Library Times."
/>
En última instancia, esto representará el siguiente <figure>elemento en el
navegador, con su estructura como se define en el AuthorCreditcomponente
y su contenido como se define en las propiedades incluidas en
la AuthorCreditllamada del componente:
htmlCopiar al portapapeles
<figure>
<img src="assets/zelda.png" alt="Portrait of Zelda Schiff" />
<figcaption>Zelda Schiff is editor-in-chief of the Library Times.</figcaption>
</figure>
Estado
Hablamos sobre el concepto de estado en el capítulo anterior: un mecanismo
de manejo de estado sólido es clave para un marco eficaz, y cada
componente puede tener datos que requieren que se controle su estado.
Este estado persistirá de alguna manera mientras el componente esté en uso.
Al igual que las propiedades, el estado se puede usar para afectar la forma en
que se representa un componente.
Como ejemplo, considere un botón que cuenta cuántas veces se hizo clic en
él. Este componente debería ser responsable de realizar un seguimiento de
su propio estado de recuento y podría escribirse de la siguiente manera:
jsxCopiar al portapapeles
function CounterButton() {
const [count] = useState(0);
return <button>Clicked {count} times</button>;
}
useState()es un gancho de React que, dado un valor de datos inicial, hará un
seguimiento de ese valor a medida que se actualiza. El código se mostrará
inicialmente de la siguiente manera en el navegador:
htmlCopiar al portapapeles
<button>Clicked 0 times</button>
La useState()llamada realiza un seguimiento del countvalor de forma sólida
en toda la aplicación, sin necesidad de que usted escriba código para hacerlo.
Eventos
Para ser interactivos, los componentes necesitan formas de responder a los
eventos del navegador, de modo que nuestras aplicaciones puedan responder
a nuestros usuarios. Cada marco proporciona su propia sintaxis para escuchar
los eventos del navegador, que hacen referencia a los nombres de los eventos
nativos equivalentes del navegador.
En React, escuchar el clickevento requiere una propiedad especial, onClick.
Actualicemos nuestro CounterButtoncódigo anterior para permitirle contar
los clics:
jsxCopiar al portapapeles
function CounterButton() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>Clicked {count}
times</button>
);
}
En esta versión, usamos useState()una funcionalidad adicional para crear
una setCount()función especial que podemos invocar para actualizar el valor
de count. Llamamos a esta función dentro del onClickcontrolador de eventos
para establecer countel valor actual más uno.
Componentes de estilo
Cada framework ofrece una forma de definir estilos para los componentes o
para la aplicación en su totalidad. Aunque el enfoque de cada framework
para definir los estilos de un componente es ligeramente diferente, todos
ofrecen múltiples formas de hacerlo. Con la incorporación de algunos
módulos auxiliares, puede diseñar sus aplicaciones de framework
en Sass o Less , o transpilar sus hojas de estilo CSS con PostCSS .
Manejo de dependencias
Todos los principales frameworks ofrecen mecanismos para gestionar
dependencias, utilizando componentes dentro de otros componentes, a
veces con múltiples niveles de jerarquía. Al igual que con otras funciones, el
mecanismo exacto variará entre frameworks, pero el resultado final es el
mismo. Los componentes tienden a importar componentes a otros
componentes utilizando la sintaxis de módulo estándar de JavaScript , o al
menos algo similar.
Componentes en componentes
Una ventaja clave de la arquitectura de interfaz de usuario basada en
componentes es que los componentes se pueden componer juntos. Al igual
que se pueden escribir etiquetas HTML unas dentro de otras para crear un
sitio web, se pueden utilizar componentes dentro de otros componentes para
crear una aplicación web. Cada marco permite escribir componentes que
utilizan (y, por lo tanto, dependen de) otros componentes.
Por ejemplo, nuestro AuthorCreditcomponente React podría utilizarse dentro
de un Articlecomponente. Eso significa que Articlesería necesario
importar AuthorCredit.
jsCopiar al portapapeles
import AuthorCredit from "./components/AuthorCredit";
Una vez hecho esto, AuthorCreditse podría utilizar dentro
del Articlecomponente de la siguiente manera:
jsxCopiar al portapapeles
<Article>
<AuthorCredit />
</Article>
Inyección de dependencia
Las aplicaciones del mundo real a menudo pueden implicar estructuras de
componentes con múltiples niveles de anidación.
Un AuthorCreditcomponente anidado en muchos niveles de profundidad
podría, por alguna razón, necesitar datos del nivel raíz de nuestra aplicación.
Digamos que el sitio de la revista que estamos construyendo está
estructurado así:
jsxCopiar al portapapeles
<App>
<Home>
<Article>
<AuthorCredit {/* props */} />
</Article>
</Home>
</App>
Nuestro Appcomponente tiene datos que AuthorCreditnecesita. Podríamos
reescribir Homey Articlepara que sepan que deben pasar los accesorios, pero
esto podría volverse tedioso si hay muchos, muchos niveles entre el origen y
el destino de nuestros datos. También es excesivo: Homey Articleen realidad
no utilizamos el retrato o la firma del autor, pero si queremos obtener esa
información en el AuthorCredit, necesitaremos
cambiar Homey Articleadaptarla.
El problema de pasar datos a través de muchas capas de componentes se
denomina perforación de apoyo y no es ideal para aplicaciones grandes.
Para evitar la perforación de propinas, los frameworks proporcionan una
funcionalidad conocida como inyección de dependencias, que es una forma
de obtener ciertos datos directamente de los componentes que los necesitan,
sin pasarlos por niveles intermedios. Cada framework implementa la
inyección de dependencias con un nombre diferente y de una manera
diferente, pero el efecto es, en última instancia, el mismo.
Angular llama a este proceso inyección de dependencia ; Vue
tiene provide()métodos inject()de componentes y ; React tiene una API de
contexto ; Ember comparte el estado a través de servicios .
Ciclo vital
En el contexto de un framework, el ciclo de vida de un componente es una
colección de fases por las que pasa un componente desde el momento en
que se agrega al DOM y luego lo renderiza el navegador (a menudo
llamado montaje ) hasta el momento en que se elimina del DOM (a menudo
llamado desmontaje ). Cada framework nombra estas fases del ciclo de vida
de manera diferente, y no todos brindan a los desarrolladores acceso a las
mismas fases. Todos los frameworks siguen el mismo modelo general:
permiten a los desarrolladores realizar ciertas acciones cuando el
componente se monta , cuando se renderiza , cuando se desmonta y en
muchas fases intermedias.
La fase de renderizado es la más importante de entender, porque es la que se
repite más veces a medida que el usuario interactúa con la aplicación. Se
ejecuta cada vez que el navegador necesita renderizar algo nuevo, ya sea que
esa nueva información sea una adición a lo que hay en el navegador, una
eliminación o una edición de lo que hay allí.
Este diagrama del ciclo de vida de un componente React ofrece una
descripción general del concepto.
Elementos de representación
Al igual que con los ciclos de vida, los frameworks adoptan enfoques
diferentes, pero similares, sobre cómo renderizan sus aplicaciones. Todos
ellos rastrean la versión renderizada actual del DOM de su navegador y cada
uno toma decisiones ligeramente diferentes sobre cómo debería cambiar el
DOM a medida que los componentes de su aplicación se vuelven a renderizar.
Debido a que los frameworks toman estas decisiones por usted,
normalmente no interactúa con el DOM por sí mismo. Esta abstracción del
DOM es más compleja y consume más memoria que actualizar el DOM por sí
mismo, pero sin ella, los frameworks no podrían permitirle programar de la
manera declarativa por la que son conocidos.
El DOM virtual es un método mediante el cual la información sobre el DOM
de su navegador se almacena en la memoria de JavaScript. Su aplicación
actualiza esta copia del DOM y luego la compara con el DOM "real" (el DOM
que se muestra realmente para sus usuarios) para decidir qué mostrar. La
aplicación crea una "diferencia" para comparar las diferencias entre el DOM
virtual actualizado y el DOM mostrado actualmente, y utiliza esa diferencia
para aplicar actualizaciones al DOM real. Tanto React como Vue utilizan un
modelo de DOM virtual, pero no aplican exactamente la misma lógica al
realizar la comparación o la visualización.
Puede leer más sobre el DOM virtual en la documentación de React .
El DOM incremental es similar al DOM virtual en el sentido de que crea una
diferencia del DOM para decidir qué se va a representar, pero se diferencia en
que no crea una copia completa del DOM en la memoria de JavaScript. Ignora
las partes del DOM que no necesitan modificarse. Angular es el único
framework analizado hasta ahora en este módulo que utiliza un DOM
incremental.
Puede leer más sobre el DOM incremental en el blog de Auth0 .
La máquina virtual Glimmer es exclusiva de Ember. No es un DOM virtual ni
un DOM incremental; es un proceso independiente a través del cual las
plantillas de Ember se transpilan en una especie de "código de bytes" que es
más fácil y rápido de leer que JavaScript.
Enrutamiento
Como se mencionó en el capítulo anterior, el enrutamiento es una parte
importante de la experiencia web. Para evitar una experiencia deficiente en
aplicaciones suficientemente complejas con muchas vistas, cada uno de los
marcos de trabajo que se tratan en este módulo proporciona una biblioteca
(o más de una biblioteca) que ayuda a los desarrolladores a implementar el
enrutamiento del lado del cliente en sus aplicaciones.
Pruebas
Todas las aplicaciones se benefician de una cobertura de pruebas que
garantiza que el software siga comportándose de la forma esperada, y las
aplicaciones web no son diferentes. El ecosistema de cada marco proporciona
herramientas que facilitan la escritura de pruebas. Las herramientas de
prueba no están integradas en los propios marcos, pero las herramientas de
interfaz de línea de comandos que se utilizan para generar aplicaciones de
marco le brindan acceso a las herramientas de prueba adecuadas.
Cada marco tiene amplias herramientas en su ecosistema, con capacidades
tanto para pruebas unitarias como de integración.
Testing Library es un conjunto de utilidades de prueba que incluye
herramientas para muchos entornos de JavaScript, incluidos React, Vue y
Angular. La documentación de Ember cubre las pruebas de las aplicaciones de
Ember .
Aquí hay una prueba rápida para nuestro CounterButtonescrito con la ayuda
de React Testing Library: prueba una serie de cosas, como la existencia del
botón y si el botón muestra el texto correcto después de hacer clic 0, 1 y 2
veces:
jsxCopiar al portapapeles
import { fireEvent, render, screen } from "@testing-library/react";
import CounterButton from "./CounterButton";
it("Renders a semantic button with an initial state of 0", () => {
render(<CounterButton />);
const btn = screen.getByRole("button");
expect(btn).toBeInTheDocument();
expect(btn).toHaveTextContent("Clicked 0 times");
});
it("Increments the count when clicked", () => {
render(<CounterButton />);
const btn = screen.getByRole("button");
fireEvent.click(btn);
expect(btn).toHaveTextContent("Clicked 1 times");
fireEvent.click(btn);
expect(btn).toHaveTextContent("Clicked 2 times");
});
Resumen
En este punto, deberías tener una idea más clara de los lenguajes, las
características y las herramientas que usarás al crear aplicaciones con marcos.
Estoy seguro de que estás entusiasmado por comenza
Ver video
https://youtu.be/XaY5cv-CORw