Composición: lo que casi siempre reemplaza al contexto
¿Prop drilling o contexto? Casi siempre la respuesta es ninguno de los dos.
Al terminar vas a poder explicar
- Reescribir una cadena de props usando children como hueco
- Explicar por qué la composición también evita re-renders
- Elegir entre composición, contexto y estado externo con un criterio
El diálogo se repite en todos los equipos. «Estoy pasando esta prop por cuatro niveles. ¿Meto un contexto?» Y casi siempre la respuesta correcta no es contexto: es cambiar cómo están armados los componentes.
La herramienta se llama composición, y es la más subestimada de React.
El problema, en concreto
1// usuario atraviesa tres componentes que no lo usan para nada.2function Pagina({ usuario }) {3 return <Layout usuario={usuario} />;4}5function Layout({ usuario }) {6 return <BarraLateral usuario={usuario} />;7}8function BarraLateral({ usuario }) {9 return <Avatar usuario={usuario} />; // recién acá se usa10}Layout y BarraLateral no necesitan saber que existe un usuario. Lo reciben, lo pasan, y quedan acoplados a un dato que no les incumbe. Cambiar la forma de usuario obliga a tocar tres archivos.
La solución: pasar el elemento ya armado
1function Pagina({ usuario }) {2 return (3 <Layout4 barra={<BarraLateral avatar={<Avatar usuario={usuario} />} />}5 />6 );7}8 9function Layout({ barra }) {10 return <div className="layout">{barra}</div>; // no sabe qué es11}12 13function BarraLateral({ avatar }) {14 return <aside>{avatar}</aside>; // tampoco15}Avatar se creó donde usuario ya estaba disponible. Los componentes del medio pasaron a recibir un hueco genérico. Ya no saben nada del usuario, y no van a romperse cuando el usuario cambie de forma.
Y de regalo, evita re-renders
Esto es lo que casi nadie nota. Cuando un componente recibe un elemento como prop, ese elemento se creó en el render del padre, no en el suyo. Si el componente intermedio se re-renderiza por su cuenta, el elemento que recibió sigue siendo el mismo objeto — y el hijo hace bailout.
1// ✗ ListaPesada se re-renderiza con cada tecla.2function Panel() {3 const [texto, setTexto] = useState("");4 return (5 <>6 <input value={texto} onChange={e => setTexto(e.target.value)} />7 <ListaPesada />8 </>9 );10}11 12// ✓ El elemento <ListaPesada /> se crea en el padre y baja como children.13// Panel se re-renderiza con cada tecla; children es la MISMA referencia.14function Panel({ children }) {15 const [texto, setTexto] = useState("");16 return (17 <>18 <input value={texto} onChange={e => setTexto(e.target.value)} />19 {children}20 </>21 );22}23 24function App() {25 return <Panel><ListaPesada /></Panel>;26}Volvé a la lección de bailout y vas a ver por qué funciona: la condición era oldProps === newProps por identidad. Como App no se re-renderiza, el elemento <ListaPesada /> es exactamente el mismo objeto en cada render de Panel. Bailout, sin memo.
Cuándo sí conviene el contexto
La composición no reemplaza todo. El contexto gana cuando:
- El dato lo necesitan muchos componentes esparcidos, no una rama concreta. Tema, idioma, sesión.
- Los consumidores son desconocidos: una librería de componentes donde no sabés quién va a leer qué.
- Componer te obligaría a inventar cinco props tipo
slotsólo para transportar un valor.
El orden mental es: composición primero, contexto si no alcanza, estado externo si el contexto tampoco. La mayoría de los equipos arranca por el tercero.
Antes de seguir · predecí
Un componente con un input que se escribe mucho tiene adentro un árbol pesado que no depende del texto. ¿Qué evita los re-renders con menos código?
Lo que te llevás
Los elementos son objetos y se pasan como props. Componer corta cadenas de prop drilling sin acoplar los componentes del medio, y de paso habilita bailouts gratis por identidad de referencia. Probá componer antes de alcanzar un Provider.
Antes de marcarla, comprobá
- ¿Podés explicar reescribir una cadena de props usando children como hueco?
- ¿Podés explicar explicar por qué la composición también evita re-renders?
- ¿Podés explicar elegir entre composición, contexto y estado externo con un criterio?