El prop drilling es un problema que ocurre cuando necesitas pasar Props a través de múltiples niveles de componentes intermedios, para llegar a un componente que realmente necesita esos datos.
React tiene un flujo de datos unidireccional, los datos fluyen del padre al hijo. Para aplicaciones pequeñas y medianas, es maravilloso. Si un componente muestra un dato erróneo, sabes que la culpa es del padre que se lo pasó mal.
Pero a medida que nuestra aplicación crece y anidamos componentes dentro de componentes, este flujo estricto empieza a crear un problema.
Para que los datos lleguen a su destino, tenemos que pasarlos a través de todos los componentes intermedios, incluso si esos componentes intermedios no necesitan esos datos para nada.
Un ejemplo
Vamos a verlo con código. Imaginad que tenemos el objeto user (con el avatar y nombre) en nuestro componente principal App, pero queremos mostrarlo en el componente Avatar que está dentro de la barra de navegación.
La estructura de nuestro ejemplo es:
App ➡ DashboardLayout ➡ Header ➡ UserMenu ➡ Avatar
Acompáñame a esta historia de terror en fascículos 👇,
App tiene el dato (user)
function App() {
const [user, setUser] = useState({ name: 'Luis', img: '...' });
// Tenemos que pasarlo al Layout...
return <DashboardLayout user={user} />;
}
El Layout no usa el usuario, pero lo recibe para pasarlo al Header
function DashboardLayout({ user }) {
return (
<div className="layout">
<Sidebar />
<div className="main">
{/* ...lo pasamos otra vez */}
<Header user={user} />
<Outlet />
</div>
</div>
);
}
El Header tampoco lo usa, pero lo recibe para el UserMenu
function Header({ user }) {
return (
<header>
<h1>Mi App</h1>
{/* ...otra vez */}
<UserMenu user={user} />
</header>
);
}
UserMenu lo pasa al Avatar
function UserMenu({ user }) {
return (
<div className="menu">
<span>Opciones</span>
{/* ...ya casi llegamos */}
<Avatar user={user} />
</div>
);
}
¡POR FIN! Aquí es donde se usa
function Avatar({ user }) {
return <img src={user.img} alt={user.name} />;
}
Y es solo un ejemplo medianamente complejo. Podrías tener 10 niveles de anidamiento, perfectamente.
Por qué esto es un problema
Es bastante evidente que bonito no es. Pero no es solo que sea “un poco tedioso” escribir tantas props. Si lo analizamos, es mucho peor que eso:
Acoplamiento innecesario
El componente Header no debería saber nada sobre el usuario. Su trabajo es pintar una cabecera. Al obligarle a recibir y pasar user, lo estamos “ensuciando”. Si mañana cambiamos la estructura del objeto usuario, tenemos que tocar Header.
Mantenimiento frágil
Si decidimos mover el componente Avatar a otro (por ejemplo, al Sidebar), tenemos que reescribir toda la cadena de props en todos los componentes intermedios.
Renombrado tedioso
Si en App cambiamos la prop de user a currentUser, tenemos que ir archivo por archivo renombrando la prop.
¿Entonces son malas las props?
Eeeeeh, no. No demonicemos pasar props. Si solo tenéis que pasar datos 1 o 2 niveles hacia abajo, hacedlo mediante props. Es explícito, fácil de seguir y rápido.
El Prop Drilling solo es un problema cuando:
- Atraviesa muchos niveles (por ejemplo, 3 o más niveles)
- Afecta a componentes que no tienen relación lógica con esos datos
- Son datos “globales” que se necesitan en muchos sitios dispersos (Usuario, Tema, Idioma, Carrito de compra)
La solución: “Teletransportación” de datos
Lo que necesitamos es una forma de hacer que el componente Avatar pueda pedir los datos directamente a App, saltándose a todos los intermediarios.
En el mundo de React, tenemos principalmente dos formas de solucionar esto:
- Context API: La solución nativa de React. Ideal para datos que cambian poco (Tema Dark/Light, Usuario autenticado, Idioma).
- Gestores de Estado (Zustand, Redux): Librerías externas optimizadas. Ideales para datos que cambian mucho y lógica compleja (Carrito de compra, Dashboard de datos en tiempo real).
Los veremos en los próximos artículos.
