JavaScript

Dominando Hooks em React: useState, useEffect, useRef e useCallback em Projetos Reais

7 min de leitura

Dominando Hooks em React: useState, useEffect, useRef e useCallback em Projetos Reais

useState: Gerenciando Estado em Componentes Funcionais O é o hook fundamental do React que permite adicionar estado a componentes funcionais. Antes dos hooks, apenas componentes de classe podiam ter estado. Ele retorna um array com dois elementos: o valor atual do estado e uma função para atualizá-lo. Um detalhe crucial: quando você chama , o React não atualiza o estado imediatamente no síncrono. Ele marca o componente para re-renderização e agenda a atualização. Se você precisar do novo valor imediatamente, use a versão funcional: . Esta abordagem é especialmente importante em loops ou quando múltiplas atualizações ocorrem em sequência. useEffect: Efeitos Colaterais e Ciclo de Vida O executa código após a renderização. Ele substitui os métodos de ciclo de vida , e de componentes de classe. O segundo argumento é a dependency array — um array que controla quando o efeito roda novamente. https://jsonplaceholder.typicode.com/users/${id} As dependency arrays funcionam assim: sem array = executa após cada render; array vazio = executa

<h2>useState: Gerenciando Estado em Componentes Funcionais</h2>

<p>O <code>useState</code> é o hook fundamental do React que permite adicionar estado a componentes funcionais. Antes dos hooks, apenas componentes de classe podiam ter estado. Ele retorna um array com dois elementos: o valor atual do estado e uma função para atualizá-lo.</p>

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

function Contador() {

const [count, setCount] = useState(0);

const [nome, setNome] = useState(&#039;&#039;);

return (

&lt;div&gt;

&lt;p&gt;Contagem: {count}&lt;/p&gt;

&lt;button onClick={() =&gt; setCount(count + 1)}&gt;Incrementar&lt;/button&gt;

&lt;input

value={nome}

onChange={(e) =&gt; setNome(e.target.value)}

placeholder=&quot;Digite seu nome&quot;

/&gt;

&lt;p&gt;Olá, {nome}!&lt;/p&gt;

&lt;/div&gt;

);

}</code></pre>

<p>Um detalhe crucial: quando você chama <code>setCount(count + 1)</code>, o React não atualiza o estado imediatamente no síncrono. Ele marca o componente para re-renderização e agenda a atualização. Se você precisar do novo valor imediatamente, use a versão funcional: <code>setCount(prevCount =&gt; prevCount + 1)</code>. Esta abordagem é especialmente importante em loops ou quando múltiplas atualizações ocorrem em sequência.</p>

<h2>useEffect: Efeitos Colaterais e Ciclo de Vida</h2>

<p>O <code>useEffect</code> executa código após a renderização. Ele substitui os métodos de ciclo de vida <code>componentDidMount</code>, <code>componentDidUpdate</code> e <code>componentWillUnmount</code> de componentes de classe. O segundo argumento é a <strong>dependency array</strong> — um array que controla quando o efeito roda novamente.</p>

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

function Usuario({ id }) {

const [user, setUser] = useState(null);

const [loading, setLoading] = useState(true);

useEffect(() =&gt; {

setLoading(true);

fetch(https://jsonplaceholder.typicode.com/users/${id})

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

.then(data =&gt; {

setUser(data);

setLoading(false);

})

.catch(err =&gt; {

console.error(err);

setLoading(false);

});

// Cleanup function (desmontagem ou antes do próximo efeito)

return () =&gt; {

console.log(&#039;Limpando recursos para o usuário:&#039;, id);

};

}, [id]); // Rodar novamente apenas quando &#039;id&#039; mudar

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

if (!user) return &lt;p&gt;Usuário não encontrado&lt;/p&gt;;

return &lt;h1&gt;{user.name}&lt;/h1&gt;;

}</code></pre>

<p>As dependency arrays funcionam assim: <strong>sem array</strong> = executa após cada render; <strong>array vazio</strong> = executa apenas uma vez (montagem); <strong>array com valores</strong> = executa quando esses valores mudam. A função retornada é o cleanup, chamada antes do efeito rodar novamente ou quando o componente desmonta. Use para cancelar requisições, remover listeners ou liberar memória.</p>

<h2>useRef: Acessando Elementos DOM e Armazenando Valores Mutáveis</h2>

<p>O <code>useRef</code> cria uma referência persistente que não causa re-renderização ao ser alterada. Diferente do <code>useState</code>, mudar um ref não dispara atualização do componente. Use para acessar diretamente elementos do DOM ou para armazenar valores que precisam persistir entre renders sem afetar a lógica de renderização.</p>

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

function FormularioComFoco() {

const inputRef = useRef(null);

const renderCountRef = useRef(0);

const [nome, setNome] = useState(&#039;&#039;);

const focarNoInput = () =&gt; {

inputRef.current.focus();

};

const handleChange = () =&gt; {

renderCountRef.current += 1;

console.log(Render #${renderCountRef.current});

};

return (

&lt;div&gt;

&lt;input

ref={inputRef}

value={nome}

onChange={(e) =&gt; {

setNome(e.target.value);

handleChange();

}}

placeholder=&quot;Digite algo&quot;

/&gt;

&lt;button onClick={focarNoInput}&gt;Focar no Input&lt;/button&gt;

&lt;p&gt;O input foi alterado {renderCountRef.current} vezes&lt;/p&gt;

&lt;/div&gt;

);

}</code></pre>

<p><strong>Cuidado</strong>: evite usar refs para tudo. Se você quer contar renders, use <code>useState</code>. Refs são para casos específicos: controlar foco, disparar animações, integrar com bibliotecas de terceiros que manipulam o DOM diretamente, ou armazenar valores que não afetam a renderização.</p>

<h2>useCallback: Otimizando Funções e Evitando Re-renderizações Desnecessárias</h2>

<p>O <code>useCallback</code> memoriza uma função, retornando a mesma referência entre renders enquanto suas dependências não mudarem. Isso é crítico quando você passa callbacks como props para componentes filhos otimizados com <code>React.memo</code>, pois evita re-renderizações desnecessárias.</p>

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

function ListaTarefas() {

const [tarefas, setTarefas] = useState([&#039;Estudar&#039;, &#039;Exercitar&#039;]);

const [input, setInput] = useState(&#039;&#039;);

// Sem useCallback, uma nova função é criada a cada render

// Se PassarParaFilho estiver em React.memo, vai re-renderizar sempre

const adicionarTarefa = useCallback(() =&gt; {

if (input.trim()) {

setTarefas([...tarefas, input]);

setInput(&#039;&#039;);

}

}, [input, tarefas]); // Recriar quando input ou tarefas mudam

return (

&lt;div&gt;

&lt;input

value={input}

onChange={(e) =&gt; setInput(e.target.value)}

placeholder=&quot;Nova tarefa&quot;

/&gt;

&lt;BotaoAdicionar onClick={adicionarTarefa} /&gt;

&lt;ul&gt;

{tarefas.map((t, i) =&gt; &lt;li key={i}&gt;{t}&lt;/li&gt;)}

&lt;/ul&gt;

&lt;/div&gt;

);

}

const BotaoAdicionar = React.memo(({ onClick }) =&gt; {

console.log(&#039;BotaoAdicionar renderizado&#039;);

return &lt;button onClick={onClick}&gt;Adicionar&lt;/button&gt;;

});</code></pre>

<p>Não otimize prematuramente. Use <code>useCallback</code> quando: (1) a função é passada como prop para componentes otimizados com <code>React.memo</code>, ou (2) a função é dependência de outros hooks como <code>useEffect</code> e <code>useCallback</code>. Se usá-lo sem necessidade, apenas adiciona complexidade.</p>

<h2>Conclusão</h2>

<p><strong>useState</strong> permite que componentes funcionais tenham estado reativo e re-renderizem quando mudam. <strong>useEffect</strong> executa efeitos colaterais em momentos específicos do ciclo de vida, com cleanup automático. <strong>useRef</strong> fornece acesso mutável a valores e elementos DOM sem disparar re-renderizações. <strong>useCallback</strong> memoriza funções para otimizar performance em cenários específicos. Domine esses quatro e você terá 80% do que precisa para React moderno. A chave é entender <strong>quando</strong> usar cada um, não apenas como.</p>

<h2>Referências</h2>

<ul>

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

<li><a href="https://react.dev/reference/react/useState" target="_blank" rel="noopener noreferrer">useState, useEffect na Documentação React</a></li>

<li><a href="https://react.dev/reference/react/useRef" target="_blank" rel="noopener noreferrer">useRef and useCallback Guide</a></li>

<li><a href="https://web.dev/react/" target="_blank" rel="noopener noreferrer">React Hooks: A Introdução Completa (Web.dev)</a></li>

<li><a href="https://kentcdodds.com/blog/react-hooks" target="_blank" rel="noopener noreferrer">Clean Code in React: Hooks Best Practices</a></li>

</ul>

Comentários

Mais em JavaScript

Closures em JavaScript: Escopo Léxico e Funções de Primeira Classe na Prática
Closures em JavaScript: Escopo Léxico e Funções de Primeira Classe na Prática

Escopo Léxico: O Alicerce das Closures O escopo léxico é a regra fundamental...

NPM e Package.json: Gerenciamento de Dependências em JavaScript na Prática
NPM e Package.json: Gerenciamento de Dependências em JavaScript na Prática

O que é NPM e por que você precisa dominar NPM (Node Package Manager) é o ger...

O que Todo Dev Deve Saber sobre DOM em JavaScript: Seleção, Manipulação e Traversal de Elementos
O que Todo Dev Deve Saber sobre DOM em JavaScript: Seleção, Manipulação e Traversal de Elementos

Seleção de Elementos no DOM A base de qualquer manipulação do DOM é saber loc...