React & Frontend

Guia Completo de Render Props em React: Quando Ainda Fazem Sentido

11 min de leitura

Guia Completo de Render Props em React: Quando Ainda Fazem Sentido

O Que São Render Props? Render Props é um padrão de design em React que consiste em passar uma função como prop para um componente, que então a chama para renderizar seu conteúdo. Essa função, chamada de "render prop", recebe dados do componente pai e retorna elementos React que serão renderizados. O nome vem justamente dessa prática: você está passando uma prop que é uma função responsável por renderizar algo. A ideia principal é desacoplar a lógica de um componente (como gerenciamento de estado, efeitos colaterais, ou comunicação com APIs) da sua apresentação visual. O componente que possui a lógica não precisa decidir o que renderizar; quem está usando o componente é quem decide. Isso tornou o padrão extremamente popular nos anos 2017-2019, principalmente antes da consolidação do React Hooks. Por Que Render Props Fizeram Sentido? O Contexto Histórico: Antes dos Hooks Antes do React 16.8 (que introduziu os Hooks), a reutilização de lógica entre componentes era um problema real.

<h2>O Que São Render Props?</h2>

<p>Render Props é um padrão de design em React que consiste em passar uma função como prop para um componente, que então a chama para renderizar seu conteúdo. Essa função, chamada de &quot;render prop&quot;, recebe dados do componente pai e retorna elementos React que serão renderizados. O nome vem justamente dessa prática: você está passando uma prop que é uma função responsável por renderizar algo.</p>

<p>A ideia principal é desacoplar a lógica de um componente (como gerenciamento de estado, efeitos colaterais, ou comunicação com APIs) da sua apresentação visual. O componente que possui a lógica não precisa decidir o que renderizar; quem está usando o componente é quem decide. Isso tornou o padrão extremamente popular nos anos 2017-2019, principalmente antes da consolidação do React Hooks.</p>

<h2>Por Que Render Props Fizeram Sentido?</h2>

<h3>O Contexto Histórico: Antes dos Hooks</h3>

<p>Antes do React 16.8 (que introduziu os Hooks), a reutilização de lógica entre componentes era um problema real. Higher-Order Components (HOCs) resolviam parte do problema, mas tinham desvantagens como wrapper hell e dificuldade em rastrear props. Render Props ofereceu uma alternativa mais explícita e flexível para compartilhar lógica sem criar camadas extras de componentes.</p>

<p>Imagine um cenário comum: você tinha um componente que gerenciava o estado de um mouse, buscava dados de uma API, ou controlava permissões de um usuário. Sem Hooks, a única forma elegante de reutilizar essa lógica em vários componentes visuais diferentes era através de Render Props ou HOCs. Render Props venceu em muitos casos porque era mais fácil de debugar e entender o fluxo de dados.</p>

<h2>Render Props na Prática: Exemplos Reais</h2>

<h3>Exemplo 1: Componente de Posição do Mouse</h3>

<p>Vamos criar um componente que rastreia a posição do mouse e passa essa informação para qualquer componente que queira usá-la:</p>

<pre><code class="language-jsx">import React, { useState, useEffect } from &#039;react&#039;;

class MousePosition extends React.Component {

constructor(props) {

super(props);

this.state = { x: 0, y: 0 };

}

componentDidMount() {

window.addEventListener(&#039;mousemove&#039;, this.handleMouseMove);

}

componentWillUnmount() {

window.removeEventListener(&#039;mousemove&#039;, this.handleMouseMove);

}

handleMouseMove = (event) =&gt; {

this.setState({ x: event.clientX, y: event.clientY });

};

render() {

return this.props.render(this.state);

}

}

// Usando o componente

function App() {

return (

&lt;MousePosition

render={({ x, y }) =&gt; (

&lt;div&gt;

&lt;p&gt;Posição do mouse: ({x}, {y})&lt;/p&gt;

&lt;div

style={{

width: &#039;50px&#039;,

height: &#039;50px&#039;,

position: &#039;absolute&#039;,

left: x,

top: y,

backgroundColor: &#039;red&#039;,

borderRadius: &#039;50%&#039;,

}}

/&gt;

&lt;/div&gt;

)}

/&gt;

);

}

export default App;</code></pre>

<p>Repare que <code>MousePosition</code> não sabe o que renderizar. Quem determina a apresentação é quem o utiliza, através da prop <code>render</code>. Essa separação clara entre lógica e apresentação era a grande vantagem do padrão.</p>

<h3>Exemplo 2: Componente de Busca de Dados</h3>

<p>Vamos criar um componente que busca dados de uma API e deixa a renderização para o consumidor:</p>

<pre><code class="language-jsx">import React, { useState, useEffect } from &#039;react&#039;;

class DataFetcher extends React.Component {

constructor(props) {

super(props);

this.state = { data: null, loading: true, error: null };

}

componentDidMount() {

fetch(this.props.url)

.then((response) =&gt; response.json())

.then((data) =&gt; this.setState({ data, loading: false }))

.catch((error) =&gt; this.setState({ error, loading: false }));

}

render() {

return this.props.render(this.state);

}

}

// Usando o componente

function PostsList() {

return (

&lt;DataFetcher

url=&quot;https://jsonplaceholder.typicode.com/posts?_limit=5&quot;

render={({ data, loading, error }) =&gt; {

if (loading) return &lt;p&gt;Carregando...&lt;/p&gt;;

if (error) return &lt;p&gt;Erro: {error.message}&lt;/p&gt;;

return (

&lt;ul&gt;

{data.map((post) =&gt; (

&lt;li key={post.id}&gt;{post.title}&lt;/li&gt;

))}

&lt;/ul&gt;

);

}}

/&gt;

);

}

export default PostsList;</code></pre>

<p>Novamente, o componente <code>DataFetcher</code> é um recipiente puro de lógica. A decisão sobre como exibir os dados fica com o consumidor.</p>

<h2>Render Props Versus Alternativas Modernas</h2>

<h3>Por Que Hooks Tornaram Render Props Menos Relevante</h3>

<p>O React Hooks, introduzido em 2019, ofereceu uma forma muito mais simples de reutilizar lógica. Em vez de criar um componente wrapper, você pode criar um custom hook. Compare:</p>

<pre><code class="language-jsx">// Com Render Props

&lt;MousePosition

render={({ x, y }) =&gt; &lt;div&gt;X: {x}, Y: {y}&lt;/div&gt;}

/&gt;

// Com Hooks (alternativa moderna)

function MyComponent() {

const { x, y } = useMousePosition();

return &lt;div&gt;X: {x}, Y: {y}&lt;/div&gt;;

}</code></pre>

<p>O código com Hooks é mais legível, menos aninhado (evita o &quot;callback hell&quot;) e mais intuitivo. Um custom hook <code>useMousePosition()</code> faz a mesma coisa que o componente <code>MousePosition</code> com Render Props, mas de forma mais direta.</p>

<h3>Quando Render Props Ainda Fazem Sentido</h3>

<p>Apesar da popularidade dos Hooks, existem cenários específicos onde Render Props ainda são a escolha correta:</p>

<ol>

<li><strong>Componentes de terceiros baseados em classe</strong>: Se você está integrando uma biblioteca que usa componentes de classe e oferece Render Props, não há razão para refatorar se está funcionando bem.</li>

</ol>

<ol>

<li><strong>Lógica vinculada ao ciclo de vida visual</strong>: Alguns padrões de UI, como tooltips ou popovers que precisam posicionar-se dinamicamente com base em refs, podem ser mais naturais com Render Props do que com Hooks customizados.</li>

</ol>

<ol>

<li><strong>Biblioteca própria com suporte a múltiplas versões</strong>: Se sua biblioteca precisa suportar versões antigas do React (antes do 16.8), Render Props é a opção viável.</li>

</ol>

<ol>

<li><strong>Composição dinâmica complexa</strong>: Em casos onde a lógica e apresentação precisam estar fortemente sincronizadas e alternar entre componentes é necessário, Render Props pode ser mais explícito que Hooks.</li>

</ol>

<pre><code class="language-jsx">// Um caso onde Render Props ainda é elegante:

// Um componente de abas/tabs onde a lógica de qual aba está ativa

// precisa coordenar a renderização de múltiplos elementos

class Tabs extends React.Component {

constructor(props) {

super(props);

this.state = { activeTab: 0 };

}

render() {

const { activeTab } = this.state;

const { tabs } = this.props;

return (

&lt;div&gt;

&lt;div className=&quot;tabs-header&quot;&gt;

{tabs.map((tab, index) =&gt; (

&lt;button

key={index}

onClick={() =&gt; this.setState({ activeTab: index })}

style={{

fontWeight: activeTab === index ? &#039;bold&#039; : &#039;normal&#039;,

}}

&gt;

{tab.label}

&lt;/button&gt;

))}

&lt;/div&gt;

&lt;div className=&quot;tabs-content&quot;&gt;

{this.props.render({ activeTab, tabs })}

&lt;/div&gt;

&lt;/div&gt;

);

}

}

// Uso:

function App() {

const tabsConfig = [

{ label: &#039;Home&#039;, content: &#039;Conteúdo da home&#039; },

{ label: &#039;Sobre&#039;, content: &#039;Conteúdo sobre&#039; },

];

return (

&lt;Tabs

tabs={tabsConfig}

render={({ activeTab, tabs }) =&gt; (

&lt;div&gt;{tabs[activeTab].content}&lt;/div&gt;

)}

/&gt;

);

}</code></pre>

<p>Neste exemplo, a coordenação entre o header (botões) e o conteúdo é forte, e o Render Props deixa explícito que o consumidor tem controle total sobre como o conteúdo ativo é exibido.</p>

<h2>O Padrão &quot;Children as a Function&quot;</h2>

<p>Uma variação de Render Props que ainda é bastante usada é passar a função como <code>children</code> em vez de uma prop nomeada:</p>

<pre><code class="language-jsx">import React, { useState, useEffect } from &#039;react&#039;;

function WindowSize({ children }) {

const [size, setSize] = useState({ width: 0, height: 0 });

useEffect(() =&gt; {

const handleResize = () =&gt; {

setSize({ width: window.innerWidth, height: window.innerHeight });

};

window.addEventListener(&#039;resize&#039;, handleResize);

handleResize(); // Chamada inicial

return () =&gt; window.removeEventListener(&#039;resize&#039;, handleResize);

}, []);

return children(size);

}

// Uso:

function App() {

return (

&lt;WindowSize&gt;

{({ width, height }) =&gt; (

&lt;div&gt;

&lt;p&gt;Largura: {width}px&lt;/p&gt;

&lt;p&gt;Altura: {height}px&lt;/p&gt;

&lt;/div&gt;

)}

&lt;/WindowSize&gt;

);

}

export default App;</code></pre>

<p>Essa abordagem é particularmente legível quando você tem uma única função como children. Bibliotecas populares como <code>react-router</code> ainda usam variações desse padrão em certas APIs.</p>

<h2>Conclusão</h2>

<p>Render Props foi um padrão revolucionário que resolveu um problema real na era pré-Hooks do React. Ele forneceu uma forma explícita e flexível de separar lógica de apresentação, evitando o wrapper hell dos HOCs. No entanto, com a chegada dos Hooks, a maioria dos casos de uso foi simplificada drasticamente.</p>

<p>A lição principal é: <strong>Render Props não desapareceram, apenas perderam relevância como a ferramenta padrão</strong>. Eles ainda são apropriados em contextos específicos, principalmente quando você herda código que já os usa ou quando está criando bibliotecas que precisam oferecer máxima flexibilidade compositiva. A decisão entre Hooks e Render Props deve ser pragmática, considerando o contexto, a legibilidade do código e o público-alvo da sua solução.</p>

<p>Finalmente, entender Render Props é importante não apenas para manutenção de código legado, mas porque o padrão em si — a ideia de deixar a renderização nas mãos do consumidor — continua sendo uma poderosa estratégia de design que transcende frameworks e linguagens.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://react.dev/reference/react" target="_blank" rel="noopener noreferrer">React Hooks Official Documentation</a></li>

<li><a href="https://legacy.reactjs.org/docs/render-props.html" target="_blank" rel="noopener noreferrer">Render Props Pattern - React Docs Archive</a></li>

<li><a href="https://www.freecodecamp.org/news/how-to-use-react-render-props-5de3f1ca2d1e/" target="_blank" rel="noopener noreferrer">Understanding React Render Props by Example</a></li>

<li><a href="https://kentcdodds.com/blog/how-to-use-react-hooks-for-shared-logic-between-components" target="_blank" rel="noopener noreferrer">When to use Render Props vs Custom Hooks</a></li>

<li><a href="https://frontendmasters.com/courses/advanced-react-patterns/" target="_blank" rel="noopener noreferrer">Advanced React Component Patterns - Frontend Masters</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em React & Frontend

Dominando XState em React: State Machines e Statecharts na Prática em Projetos Reais
Dominando XState em React: State Machines e Statecharts na Prática em Projetos Reais

O Que São State Machines e Por Que Devemos Usar? Uma máquina de estados é um...

Boas Práticas de React Query: Mutations, Invalidações e Sincronização de Cache para Times Ágeis
Boas Práticas de React Query: Mutations, Invalidações e Sincronização de Cache para Times Ágeis

Introdução ao React Query e o Ciclo de Vida das Mutações React Query é uma bi...

Controlled vs Uncontrolled Components: Quando Usar Cada Abordagem na Prática
Controlled vs Uncontrolled Components: Quando Usar Cada Abordagem na Prática

O Que São Componentes Controlados e Não Controlados? Antes de mais nada, prec...