Os React Hooks são tipo uma super ferramenta para todos os devs React, mas especialmente para quem tá começando ou já tá na pegada intermediária. Eles são uma das principais ferramentas pra melhorar a legibilidade, reutilização e manutenção do seu código.
Pensa comigo: é como trocar blocos de construção convencionais por uns feitos sob medida, que deixam sua aplicação mais estável e organizada. E é isso que os React Hooks podem fazer por você!
Tem um exemplo completo aqui de como fazer uma lista de tarefas usando React Hooks. Dá uma conferida!
Os React Hooks vieram pra facilitar a vida na hora de gerenciar o estado e os efeitos colaterais nos componentes funcionais do React. A ideia era simplificar e deixar nosso código mais limpo, mais fácil de ler, reutilizar e manter.
Antes dos Hooks, a parada era usar componentes de classe, que eram meio que como um quebra-cabeça – dava pra resolver, mas às vezes era meio chato, especialmente quando você tinhas muitas peças. Era tipo procurar uma agulha no palheiro de código.
Por exemplo, quer um contador que aumenta quando você clica num botão? Suuuuper fácil com o useState
. E quando você quer que algo aconteça sempre que esse contador muda, é só usar o useEffect
. Dá uma olhada na diferença entre fazer isso com React Hooks e componentes de classe.
// Sem React Hooks
class Contador extends React.Component {
state = {
count: 0,
}
componentDidMount() {
document.title = `Contagem: ${this.state.count}`
}
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
document.title = `Contagem: ${this.state.count}`
}
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>Incrementar</button>
</div>
)
}
}
// Com React Hooks
function Counter() {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `Contagem: ${count}`
}, [count])
return (
<div>
<p>Contagem: {count}</p>
<button onClick={() => setCount(count + 1)}>Incrementar</button>
</div>
)
}
React Hooks, especialmente o useState
e o useEffect
, são como uma caixa de ferramentas que deixa a experiência de desenvolvimento React bem mais produtiva. Eles te incentivam a escrever um código mais organizado e que dá pra reutilizar, resultando em aplicativos mais limpos e fáceis de manter.
Ah, e os React Hooks incluem também o useRef
, useContext
, useReducer
e mais uns outros. Dá uma conferida na lista completa. Esses hooks podem ser usados pra gerenciar o estado, fazer uns truques com efeitos colaterais e acessar dados do contexto de várias maneiras.
useState
apenas para gerenciar o estado que é essencial para seu componenteO useState
é um poderoso React Hook que te permite controlar o estado nos componentes funcionais. Dá pra usar pra ficar de olho em tudo que muda com o tempo, tipo o valor de um campo de formulário, a pontuação num jogo ou a lista de coisas no carrinho de compras.
Cada vez que você usa o useState
, você tá criando uma variável de estado nova. Isso pode acumular e deixar teus componentes lentos e difíceis de entender, então saiba usar da maneira correta, criando apenas states essenciais para o seu componente.
Faça:
import React, { useState } from 'react';
const Contador = () => {
const [contador, setContador] = useState(0); // Estado essencial: contador
const handleIncrement = () => {
setContador(prevContador => prevContador + 1);
};
return (
<div>
<p>Contagem: {contador}</p>
<button onClick={handleIncrement}>Incrementar</button>
</div>
);
};
export default Contador;
Aqui a gente tá usando o useState
pra gerenciar o estado essencial (contador) que é necessário pro componente, que é o jeito certo.
Manter apenas o estado essencial no teu componente ajuda a manter teu código organizado e fácil de manter. Também facilita entender como o teu componente funciona e como ele muda com o tempo.
Não faça:
import React, { useState } from 'react';
const PerfilUsuario = () => {
const [logado, setLogado] = useState(false); // Estado não essencial: logado
const handleLogin = () => {
setLogado(true);
};
const handleLogout = () => {
setLogado(false);
};
return (
<div>
<p>O usuário está logado: {logado ? 'Sim' : 'Não'}</p>
<button onClick={handleLogin}>Entrar</button>
<button onClick={handleLogout}>Sair</button>
</div>
);
};
export default PerfilUsuario;
Já nesse componente, o estado logado
usando React Hooks é considerado não essencial porque não está diretamente relacionado à funcionalidade principal ou propósito do componente UserProfile
. O objetivo desse componente é mostrar as informações do perfil do usuário, o foco principal não é gerenciar o status de login do usuário.
Fica de olho em estados não essenciais usando React Hooks no teu componente, porque isso pode complicar e dificultar a leitura do teu código. Além disso, pode causar problemas de desempenho, especialmente quando temos uma grande quantidade de estados.
useState
pra controlar um estado imutávelPense em um state como algo que não pode ser alterado diretamente. Isso quer dizer que você nunca deve alterar diretamente a variável de estado. Em vez disso, sempre que quiser fazer uma alteração, crie uma cópia nova dessa variável. Isso ajuda a manter a confiabilidade dos seus dados e evita mudanças inesperadas, garantindo que o seu programa funcione como esperado.
Faça:
import React, { useState } from 'react';
const ContadorImutavel = () => {
const [contador, setContador] = useState(0); // Estado imutável: contador
const handleIncremento = () => {
// Atualize o contador de forma imutável usando a função setContador
setContador(prevContador => prevContador + 1);
};
return (
<div>
<p>Contagem: {contador}</p>
<button onClick={handleIncremento}>Incrementar</button>
</div>
);
};
export default ContadorImutavel;
Nesse exemplo, a gente tá usando o setContador
para atualizar o contador que não deve ser mudado diretamente. Isso segue as regras do React, deixando tudo mais organizado e confiável. Manter os estados imutáveis também facilita entender e encontrar erros no teu código.
Não Faça:
const ContadorMutavel = () => {
const [contador, setContador] = useState(0);
useEffect(() => {
setContador(contador + 1);
});
return (
<div>
<p>Contagem: {contador}</p>
</div>
);
};
A razão de não ser correto atualizar as variáveis de estado diretamente no useEffect
, por exemplo, é porque isso pode gerar loops infinitos.
Nesse exemplo, o useEffect
vai ser acionado depois de cada renderização, e ele vai incrementar a variável de estado de contagem (contador), isso quer dizer que a variável de estado vai ser incrementada continuamente, criando um loop infinito.
useState
pra organizar teu estado de uma maneira normalizadaSignifica dizer que você deve organizar o estado(s) de forma padronizada e arrumada. Ao invés de amontoar todos os dados num monte só, divida em pedacinhos menores e bem organizados. Cada pedaço de dado com seu identificador único, o que facilita encontrar, atualizar ou trabalhar com eles.
Faça:
import React, { useState } from 'react';
const ProdutosNormalizados = () => {
const [produtos, setProdutos] = useState({
1: { id: 1, nome: 'Produto A' },
2: { id: 2, nome: 'Produto B' }
}); // Estado normalizado: produtos
return (
<div>
<ul>
{Object.values(produtos).map(produto => (
<li key={produto.id}>{produto.nome}</li>
))}
</ul>
</div>
);
};
export default ProdutosNormalizados;
Um exemplo de como usar o useState
e deixar nossos dados organizados. Cada produto tem seu próprio ID especial, o que facilita encontrar e mexer neles. Assim, a gente consegue buscar nossos produtos e fazer mudanças quando preciso. É como ter uma caixa de ferramentas bem organizada onde cada ferramenta tem seu lugar – dá pra achar a ferramenta certa rapidão.
Não Faça:
import React, { useState } from 'react';
const ProdutosNaoNormalizados = () => {
const [produtos, setProdutos] = useState([
{ id: 1, nome: 'Produto A' },
{ id: 2, nome: 'Produto B' }
]); // Estado não normalizado: produtos
return (
<div>
<ul>
{produtos.map(produto => (
<li key={produto.id}>{produto.nome}</li>
))}
</ul>
</div>
);
};
export default ProdutosNaoNormalizados;
Um state “desnormalizado” usando React Hooks significa que os dados não estão organizados de maneira eficiente. Nesse exemplo, a gente tá usando o useState pra gerenciar uma lista de produtos também, mas aqui cada produto é representado como um objeto dentro de um array e não existe um identificador para esse produto.
Se tu tem muitos produtos na lista, usar um estado desorganizado com React Hooks pode dificultar achar e atualizar produtos específicos. Também pode causar problemas de desempenho, especialmente se tu tá mostrando uma lista com todos os teus produtos.
useEffect
apenas para efeitos colaterais.useEffect
não foi feito pra atualizar o estado ou fazer o componente aparecer na tela. Pense nele como a ferramenta que cuida das coisas que rolam nos bastidores enquanto teu componente faz sua mágica. Então, se precisar buscar dados de uma API ou ficar de olho em atualizações, é aí que o useEffect
entra em ação.
Faça:
import React, { useEffect } from 'react';
const SubscriptionManager = () => {
useEffect(() => {
// Simulando uma assinatura de um evento
const subscription = someEventEmitter.on('event', () => {
// Lidar com o evento
console.log('Evento recebido!');
});
// Limpeza: Cancelar a assinatura quando o componente é desmontado
return () => {
someEventEmitter.off('event', subscription);
};
}, []); // Array de dependências vazio
return <p>Gerenciador de Assinaturas</p>;
};
export default SubscriptionManager;
Nesse exemplo, a gente ta usando o useEffect
pra gerenciar uma inscrição num evento. É um cenário típico de efeito colateral, onde a gente se inscreve num evento e garante cancelar a inscrição quando o componente é desmontado.
Não Faça:
import React, { useEffect, useState } from 'react';
const ExemploInvalido = () => {
const [mensagem, setMensagem] = useState('Mensagem inicial');
useEffect(() => {
// Isso está incorreto: o efeito está atualizando o estado e causando re-renderizações
setMensagem('Mensagem atualizada');
}, []); // Array de dependências vazio
return <p>{mensagem}</p>;
};
export default ExemploInvalido;
Aqui a gente tá usando o useEffect
pra atualizar o estado do componente diretamente. Isso é uma maneira errada de usar o useEffect
, porque ele é feito pra lidar com efeitos colaterais, não pra causar novas renderizações ou atualizar o estado diretamente. Sempre use o useEffect
só pra tarefas relacionadas aos efeitos colaterais.
O useEffect
pega uma lista de dependências como argumento, e ele só vai rodar quando alguma dessas dependências mudar. Isso significa que a gente avisa o React sobre coisas específicas (como variáveis ou pedaços de dados) que ele precisa ficar de olho. Se alguma dessas coisas mudar, o React sabe que tem que fazer algo.
Faça:
import React, { useState, useEffect } from 'react';
const ExemploComDependencias = () => {
const [contador, setContador] = useState(0);
const [multiplicador, setMultiplicador] = useState(1);
useEffect(() => {
// Este efeito será executado sempre que 'contador' ou 'multiplicador' mudarem
console.log('Efeito executado! Contador:', contador, 'Multiplicador:', multiplicador);
}, [contador, multiplicador]); // Especifique as dependências: 'contador' e 'multiplicador'
return (
<div>
<p>Contador: {contador}</p>
<p>Multiplicador: {multiplicador}</p>
<button onClick={() => setContador(contador + 1)}>Incrementar Contador</button>
<button onClick={() => setMultiplicador(multiplicador * 2)}>Dobrar Multiplicador</button>
</div>
);
};
export default ExemploComDependencias;
Aqui a gente tá colocando [count, multiplicador]
como dependências no useEffect
. Especificar dependências no useEffect
pode melhorar a performance e eficiência do teu código, porque evita que o efeito rode sem necessidade.
Não Faça:
import React, { useState, useEffect } from 'react';
const ExemploDependenciaIncorreta = () => {
const [contador, setContador] = useState(0);
const [multiplicador, setMultiplicador] = useState(1);
useEffect(() => {
// Este efeito será executado após cada renderização
console.log('Efeito executado! Contador:', contador, 'Multiplicador:', multiplicador);
}); // Nenhuma dependência especificada
return (
<div>
<p>Contador: {contador}</p>
<p>Multiplicador: {multiplicador}</p>
<button onClick={() => setContador(contador + 1)}>Incrementar Contador</button>
<button onClick={() => setMultiplicador(multiplicador * 2)}>Dobrar Multiplicador</button>
</div>
);
};
export default ExemploDependenciaIncorreta;
Sempre coloque todas as dependências relevantes pra garantir que o efeito funcione como esperado.
Nesse caso, o useEffect
não tem nenhuma dependência o useEffect
então vai rodar o efeito depois de cada renderização, mesmo se nenhuma das dependências mudou. Isso pode causar problemas de desempenho, especialmente se o efeito for computacionalmente custoso.
O useEffect
devolve uma função de limpeza. Ele chama essa função antes de rodar o efeito novamente ou quando o componente for desmontado. Se o efeito cria recursos, como timers ou inscrições, é bom limpar esses recursos usando a função de limpeza.
Faça:
import React, { useEffect } from 'react';
const ExemploAssinatura = () => {
useEffect(() => {
const assinatura = assinarAlgo();
// Limpeza: Cancelar a assinatura quando o componente é desmontado
return () => {
cancelarAssinatura(assinatura);
};
}, []); // Array de dependências vazio
return <p>Exemplo de Assinatura</p>;
};
const assinarAlgo = () => {
// Simular a configuração da assinatura
console.log('Assinado!');
return 'token_de_assinatura';
};
const cancelarAssinatura = (assinatura) => {
// Simular a limpeza da assinatura
console.log('Assinatura cancelada!', assinatura);
};
export default ExemploAssinatura;
Pra arrumar a bagunça depois de uma inscrição, a gente cancela a inscrição quando o componente é desmontado. Isso garante que não vai ter inscrições penduradas causando problemas.
Não Faça:
import React, { useEffect } from 'react';
const ExemploLimpezaIncorreta = () => {
useEffect(() => {
const intervalo = setInterval(() => {
console.log('Olá!');
}, 1000);
// Ops! Sem limpeza, isso causará vazamento de memória
}, []); // Array de dependências vazio
return <p>Exemplo de Limpeza Incorreta</p>;
};
export default ExemploLimpezaIncorreta;
Nesse caso, a gente esqueceu de limpar depois de criar um intervalo. Isso pode causar um vazamento de memória, porque o intervalo continua rodando mesmo depois do componente ser desmontado. Sempre lembre de limpar os recursos ou inscrições pra manter tua aplicação sem bugs.
Isso significa que dá pra criar suas próprias ferramentas reutilizáveis usando React Hooks pra lidar com tarefas específicas nos teus componentes React. É tipo criar tuas próprias peças de LEGO personalizadas que se encaixam perfeitamente nos teus projetos, deixando o teu trabalho ainda mais fácil e organizado.
Por exemplo, se tu precisa sempre gerenciar a autenticação do usuário, dá pra construir um hook personalizado usando React Hooks que cuida do login, logout e verifica se o usuário está logado. Assim, não precisa ficar recriando o mesmo código em todo componente – tu só usa teu hook personalizado, como uma ferramenta especial na tua caixa de ferramentas de React, quando precisar. É uma maneira bem legal e eficiente de tornar teus projetos React mais manejáveis.
import React, { useState } from 'react';
// Crie um hook personalizado para gerenciar o estado de autenticação
const useAutenticacao = () => {
const [logado, setLogado] = useState(false);
// Função para lidar com o login
const fazerLogin = () => {
setLogado(true);
};
// Função para lidar com o logout
const fazerLogout = () => {
setLogado(false);
};
// Retorna o estado de autenticação e funções para login e logout
return {
logado,
fazerLogin,
fazerLogout
};
};
// Um componente que utiliza o hook de autenticação personalizado
const ComponenteAutenticacao = () => {
// Use o hook personalizado para obter o estado de autenticação e funções
const { logado, fazerLogin, fazerLogout } = useAutenticacao();
return (
<div>
<p>O usuário está logado: {logado ? 'Sim' : 'Não'}</p>
<button onClick={fazerLogin}>Logar</button>
<button onClick={fazerLogout}>Sair</button>
</div>
);
};
export default ComponenteAutenticacao;
Pra gerenciar o status de autenticação nesse exemplo, a gente criou um novo hook chamado useAutenticacao
. Esse hook único é usado pelo ComponenteAutenticacao
pra gerenciar o processo de login e logout.
import React, { useState } from 'react';
// Este componente está lidando incorretamente com a autenticação sem usar um hook personalizado
const ComponenteAutenticacaoInvalido = () => {
// Estado para controlar se o usuário está logado ou não
const [logado, setLogado] = useState(false);
// Função para lidar com o login
const fazerLogin = () => {
setLogado(true); // Define logado como true quando o botão 'Entrar' é clicado
};
// Função para lidar com o logout
const fazerLogout = () => {
setLogado(false); // Define logado como false quando o botão 'Sair' é clicado
};
return (
<div>
{/* Exibe se o usuário está logado ou não */}
<p>O usuário está logado: {logado ? 'Sim' : 'Não'}</p>
<button onClick={fazerLogin}>Entrar</button> {/* Botão para iniciar login */}
<button onClick={fazerLogout}>Sair</button> {/* Botão para iniciar logout */}
</div>
);
};
export default ComponenteAutenticacaoInvalido; // Exporta o componente para uso em outras partes da aplicação
Em vez de colocar a lógica num hook personalizado, a gente tá usando o useState
diretamente dentro do componente nesse exemplo. Além de ir contra as práticas recomendadas, que sugerem encapsular a lógica relacionada dentro de um hook personalizado pra reutilização, isso pode resultar em duplicação de código. Criar essas ferramentas especiais (hooks personalizados) é o caminho certo.
Os React Hooks, como o useState
e o useEffect
, são ferramentas poderosas que podem tornar seu código mais modular, reutilizável, limpo e fácil de manter.
Use o useState
para gerenciar o estado essencial do componente, garantindo imutabilidade e normalização. Use o useEffect
para lidar com efeitos colaterais, como busca de dados e inscrições.
Seguindo esses princípios, você pode alcançar um novo nível de eficiência e elegância na sua jornada de desenvolvimento com React.
Bons hooks! 🚀
Deixe um comentário