Also available in Inglés
La afirmación a prueba
El ensayo del martes sostuvo que la arquitectura de componentes puede organizar el código fuente sin reemplazar la estructura del documento que produce, y que el fallo no está en dividir una página en componentes, sino en dividir una sola decisión entre componentes sin verificar si alguno de ellos conservó suficiente información para tomarla. El ejemplo fue el nivel de un encabezado, decidido a seis componentes de distancia de la posición en la página que debió haberlo establecido.
La cadena
Seis componentes, compuestos de la forma en que realmente se usarían:
<DashboardLayout>
<CardGroup>
<Card title="Active Subscriptions">
{/* subscription list */}
</Card>
</CardGroup>
</DashboardLayout>
Cada capa realiza un solo trabajo:
function DashboardLayout({ children }) {
return (
<main>
<h1>Dashboard</h1>
{children}
</main>
);
}
function CardGroup({ children }) {
return <div className="card-grid">{children}</div>;
}
function Card({ title, children }) {
return (
<div className="card">
<CardHeader title={title} />
<div className="card-body">{children}</div>
</div>
);
}
function CardHeader({ title }) {
return (
<div className="card-header">
<Typography variant="subheading">{title}</Typography>
</div>
);
}
function Typography({ variant, children }) {
return <Heading variant={variant}>{children}</Heading>;
}
function Heading({ variant, children }) {
const Tag = variant === 'subheading' ? 'h6' : 'h2';
return <Tag>{children}</Tag>;
}
Al renderizarse, esto produce exactamente lo que describió el ensayo:
<main>
<h1>Dashboard</h1>
<div class="card-grid">
<div class="card">
<div class="card-header">
<h6>Active Subscriptions</h6>
</div>
<div class="card-body">...</div>
</div>
</div>
</main>
Seis preguntas, la misma respuesta
Haz a cada capa las mismas dos preguntas. ¿Sabe dónde se ubica esta sección en la estructura general de la página? ¿Sabe qué etiqueta HTML tendrá su encabezado?
-
DashboardLayout conoce la estructura. Renderiza el único
<h1>de la página, lo que significa que también sabe implícitamente que todo lo que renderice comochildrenpertenece jerárquicamente debajo de ese<h1>. No conoce la etiqueta: nunca toca un encabezado directamente, solo delega lo que recibe. -
CardGroup no conoce ninguna de las dos cosas. Es un contenedor de cuadrícula (
grid wrapper). No sabe que está dentro de un dashboard y no tiene ninguna opinión sobre los encabezados. -
Card no conoce ninguna de las dos cosas. Borde, padding, un
CardHeader, un cuerpo. Tampoco hay lógica de encabezados aquí. -
CardHeader conoce la cadena de texto —"Active Subscriptions"— pero no en qué lugar de la página se ubica la tarjeta que la contiene. No decide una etiqueta. Le pasa el texto a
Typographycon una instrucción de estilo: renderiza esto como un subencabezado (subheading). -
Typography conoce la instrucción de estilo, no la estructura, y tampoco decide una etiqueta. Existe para que el sistema de diseño tenga un solo lugar que defina cómo se ve un subheading. Transmite la propiedad
variantdirectamente. -
Heading es donde subheading realmente se convierte en
<h6>. Esta es la única capa en toda la cadena donde se elige una etiqueta real, y también es la capa más alejada de la página, la que no tiene forma de saber que "Active Subscriptions" terminará seis niveles por debajo de un título de página que nunca ha visto.
Seis capas, seis respuestas idénticas a la segunda pregunta, hasta que la sexta cambia, exactamente en la capa menos equipada para responderla correctamente.
Dos caminos de regreso
Pasar el nivel de forma explícita. Entrega a cada capa una propiedad level y pásala directamente, sin cambios, desde la cima:
function DashboardLayout({ children }) {
return (
<main>
<h1>Dashboard</h1>
{children}
</main>
);
}
function CardGroup({ level, children }) {
return <div className="card-grid">{children}</div>;
}
function Card({ level, title, children }) {
return (
<div className="card">
<CardHeader level={level} title={title} />
<div className="card-body">{children}</div>
</div>
);
}
function CardHeader({ level, title }) {
return (
<div className="card-header">
<Typography level={level}>{title}</Typography>
</div>
);
}
function Typography({ level, children }) {
return <Heading level={level}>{children}</Heading>;
}
function Heading({ level, children }) {
const Tag = `h${level}`;
return <Tag>{children}</Tag>;
}
<DashboardLayout>
<CardGroup level={2}>
<Card level={2} title="Active Subscriptions">
{/* subscription list */}
</Card>
</CardGroup>
</DashboardLayout>
El estilo visual se omite en esta versión para mantener visible el paso de level; en la práctica viajaría por la misma ruta, pero bajo su propia propiedad, separada de la estructura tal como sostuvo el ensayo.
El costo de esta solución: CardGroup, Card, CardHeader y Typography tuvieron que cambiar, a pesar de que ninguno tenía un interés real en la decisión. Agrega un séptimo contenedor a la cadena el próximo trimestre y también tendrá que recordar pasar level, o la cadena se romperá de nuevo en un lugar diferente.
Rastrearlo a través de contexto. Deja que las capas que nunca tuvieron un interés en la decisión se mantengan exactamente como estaban en "La cadena": CardGroup, Card, CardHeader y Typography permanecen intactas, sin simplificar ni reescribir. Solo cambian dos componentes:
const HeadingLevelContext = createContext(1);
function DashboardLayout({ children }) {
return (
<main>
<h1>Dashboard</h1>
<HeadingLevelContext.Provider value={2}>
{children}
</HeadingLevelContext.Provider>
</main>
);
}
function Heading({ children }) {
const level = useContext(HeadingLevelContext);
const Tag = `h${level}`;
return <Tag>{children}</Tag>;
}
DashboardLayout establece el nivel una sola vez. Heading lo lee desde el contexto en lugar de adivinarlo a partir de una cadena variant. Nada en el medio necesita saber que el contexto existe.
El costo aquí es diferente, no inexistente. Leer Heading de forma aislada ya no te dice qué etiqueta renderiza: debes saber que existe un proveedor (provider) en algún lugar superior del árbol. La primera solución es más fácil de rastrear leyendo solo las propiedades (props). La segunda pide a menos componentes participar en una decisión que nunca les perteneció.
Si la afirmación se sostuvo
La afirmación del ensayo Por qué los árboles DOM con abstracción de componentes se vuelven más difíciles de leer de leer era que la arquitectura de componentes organiza el código fuente y no puede, por sí sola, reemplazar la estructura del documento, y que el fallo es una decisión dividida entre componentes, no un componente roto. Seis capas, recorridas una a una, nunca produjeron una sola capa que conservara ambas mitades de la información que la decisión necesitaba. DashboardLayout tenía la estructura. Heading tenía la etiqueta. Nada en el medio tenía ambas.
Ambas soluciones confirman también la segunda mitad de la afirmación. Ninguna reduce los seis componentes a menos. Una transmite el contexto faltante a través de todos ellos. La otra lo transmite solo a través de los dos que realmente lo necesitaban. De cualquier manera, la solución nunca se trató de cuántos componentes existen. Se trató de a cuál se le entrega la información que le faltaba.
Top comments (0)