Entendendo o Prop Drilling no React.js (e como evitar esse problema)

Foto de Ismael Paramo na Unsplash

Introdução

Se você já trabalhou com React por algum tempo, provavelmente se deparou com o famoso prop drilling, aquele momento em que uma prop precisa atravessar uma cadeia inteira de componentes apenas para chegar onde realmente será usada.

Mas afinal, o que exatamente é prop drilling e por que isso é considerado um problema em aplicações React?

Neste artigo, vamos entender:

  • O conceito de prop drilling e por que ele ocorre.
  • O impacto que causa no código e na equipe de desenvolvimento.
  • Analogia simples para explicar a quem não é técnico.
  • Estratégias modernas para evitar o problema, com exemplos práticos.

O que é Prop Drilling?

Em React, os dados normalmente fluem de cima para baixo, ou seja, de um componente pai para seus filhos através das props.
O prop drilling acontece quando você precisa passar uma prop por vários níveis intermediários de componentes, mesmo que esses intermediários não usem a prop, apenas a repassem.

Exemplo prático:

TypeScript
function App() {
  const user = { name: "Luigi", role: "Frontend Developer" };

  return <Layout user={user} />;
}

function Layout({ user }) {
  return <Sidebar user={user} />;
}

function Sidebar({ user }) {
  return <UserProfile user={user} />;
}

function UserProfile({ user }) {
  return <p>Olá, {user.name}!</p>;
}

➡️ Aqui, user precisa atravessar Layout e Sidebar até chegar em UserProfile, mesmo que apenas o último use realmente o dado.


Por que o Prop Drilling é um Problema?

Embora inofensivo em componentes pequenos, o prop drilling causa dores reais em aplicações grandes:

  1. Acoplamento excessivo: os componentes ficam dependentes de dados que nem utilizam.
  2. Dificuldade de manutenção: se a estrutura de componentes mudar, você precisa ajustar todas as props intermediárias.
  3. Menor reusabilidade: componentes intermediários deixam de ser genéricos, já que estão “contaminados” com props que não lhes dizem respeito.
  4. Maior chance de bugs: basta esquecer de passar uma prop em algum ponto para quebrar o fluxo.
  5. Problemas de desempenho: renderizações desnecessárias se os componentes intermediários não estão otimizados.

Uma Analogia Simples (para quem não é técnico)

Imagine que você quer entregar uma encomenda ou uma caixa a alguém que mora em um prédio.

Mas, em vez de usar o correio, você decide entregar pessoalmente a caixa ao porteiro, mas ela deve passar pelas mãos de cada morador, até que o último finalmente entregue ao destinatário final.

Cada pessoa que pega a caixa e passa adiante não abre, nem usa o conteúdo ou informação, apenas repassa. Agora imagine isso em um prédio de 10 andares: cansativo, propenso a erros, possivelmente causando reações desnecessárias aos moradores intermediários e completamente dispensável, correto?

No React, o prop drilling é exatamente isso: componentes atuando como mensageiros, passando dados que não são seus.


Soluções para Evitar o Prop Drilling

A boa notícia é que o React (e o ecossistema em torno dele) oferece várias soluções para evitar esse tipo de acoplamento. Costumo utilizar algumas, vejamos.


1. Context API (nativo do React)

O Context API permite compartilhar valores entre componentes sem precisar passar props manualmente a cada nível.

TypeScript
import { createContext, useContext } from "react";

const UserContext = createContext();

function App() {
  const user = { name: "Luigi", role: "Frontend Developer" };

  return (
    <UserContext.Provider value={user}>
      <Layout />
    </UserContext.Provider>
  );
}

function UserProfile() {
  const user = useContext(UserContext);
  return <p>Olá, {user.name}!</p>;
}

✅ Agora, UserProfile acessa user diretamente, sem depender da cadeia de props.


2. State Management Libraries

Para aplicações grandes, o Context pode se tornar complexo ou causar re-renderizações desnecessárias.
Nesses casos, ferramentas como Zustand, Redux, Jotai ou Recoil oferecem soluções mais escaláveis.

Exemplo com Zustand:

TypeScript
import create from "zustand";

const useUserStore = create((set) => ({
  user: { name: "Luigi", role: "Frontend Developer" },
  setUser: (user) => set({ user }),
}));

function UserProfile() {
  const { user } = useUserStore();
  return <p>Olá, {user.name}!</p>;
}

💡 Aqui, qualquer componente pode acessar user diretamente — sem prop drilling e com controle global de estado.


3. Component Composition

Outra técnica é compor componentes, em vez de passar propriedades por níveis.

TypeScript
function Layout({ sidebar }) {
  return (
    <div className="layout">
      {sidebar}
      <main>Conteúdo principal</main>
    </div>
  );
}

function App() {
  const user = { name: "Luigi" };

  return (
    <Layout sidebar={<UserProfile user={user} />} />
  );
}

Assim, o componente Layout não precisa conhecer user — apenas renderiza o que recebe como composição.


Quando o Prop Drilling é Aceitável?

É importante dizer: nem sempre o prop drilling é ruim.
Em componentes pequenos ou locais (por exemplo, um formulário com 2 ou 3 níveis), passar propriedades explicitamente pode ser mais simples e previsível do que usar Context.

A regra de ouro é:

  • Se o dado é compartilhado amplamente na aplicação, use Context ou um estado global.
  • Se é algo local e temporário, continue passando props normalmente.

Conclusão

O prop drilling é um dos primeiros desafios que encontramos ao crescer uma aplicação React.
Ele surge naturalmente quando o estado é compartilhado demais e com o tempo a complexidade escala rapidamente.

Para resolver:

  1. Entenda o fluxo de dados na sua aplicação.
  2. Use Context API ou uma store global quando o dado for compartilhado.
  3. Prefira composição de componentes sempre que possível.

📢 Curtiu essa explicação?
Me siga no LinkedIn para mais conteúdos práticos sobre desenvolvimento frontend.


Referências