Hooks FAQ
These docs are old and won’t be updated. Go to react.dev for the new React docs.
The new documentation pages teaches React with Hooks.
Hooks são uma nova adição ao React 16.8. Eles permitem que você use o state e outros recursos do React sem escrever uma classe.
Esta página responde algumas das perguntas mais frequentes sobre Hooks.
-
- Quais versões do React incluem Hooks?
- Preciso reescrever todos os meus componentes com classe?
- O que eu posso fazer com Hooks que eu não podia fazer com classes?
- Quanto do meu conhecimento de React continua relevante?
- Devo usar Hooks, classes ou um misto dos dois?
- Hooks cobrem todos os casos de uso para classes?
- Hooks substituem render props e HOC (componente de alta-ordem, do inglês high-order component)?
- O que Hooks significam para APIs populares como o connect() do Redux e o React Router?
- Hooks funcionam com tipagem estática?
- Como testar componentes que usam Hooks?
- O que exatamente as regras de lint impõem?
-
- Como os métodos de ciclo de vida correspondem aos Hooks?
- Como posso fazer a busca de dados com Hooks?
- Existe algo como variáveis de instância?
- Devo usar uma ou muitas variáveis de estado?
- Posso usar um efeito somente em updates?
- Como acessar as props ou o estado anterior?
- Por que estou vendo props obsoletos ou state dentro da minha função?
- Como implementar getDerivedStateFromProps?
- Existe algo como forceUpdate?
- Posso fazer uma ref para um componente de função?
- Como posso medir um nó DOM?
- O que const [thing, setThing] = useState() significa?
-
- Posso pular um efeito nos updates?
- É seguro omitir funções da lista de dependências?
- O que posso fazer se minhas dependências de efeito mudarem com muita frequência?
- Como implementar shouldComponentUpdate?
- Como memorizar cálculos?
- Como criar objetos custosos a demanda?
- Hooks são mais lentos por criar funções no render?
- Como evitar passar callbacks para baixo?
- Como ler um valor frequentemente variável de useCallback?
Estratégia de Adoção
Quais versões do React incluem Hooks?
Começando com 16.8.0, React inclui uma implementação estável dos Hooks para:
- React DOM
- React Native
- React DOM Server
- React Test Renderer
- React Shallow Renderer
Note que para habilitar Hooks, todos os pacotes precisam estar na versão 16.8.0 ou maior. Hooks não vão funcionar se você esquecer de atualizar, por exemplo, o React DOM.
React Native 0.59 e superiores suportam Hooks.
Preciso reescrever todos os meus componentes usando classe?
Não. Não existe nenhum plano para remover classes do React — todos nós precisamos continuar entregando produtos e não podemos reescrever tudo. Recomendamos tentar usar Hooks em código novo.
O que eu posso fazer com Hooks que eu não podia fazer com classes?
Hooks oferecem uma nova maneira, poderosa e expressiva, de reutilizar funcionalidade entre componentes. “Construindo Seu Próprio Hook” fornece um vislumbre do que é possível. Este artigo feito por um membro da equipe principal do React mergulha fundo nas novas possibilidades desbloqueadas por Hooks.
Quanto do meu conhecimento de React continua relevante?
Hooks são uma maneira mais direta de usar as funcionalidades do React que você já conhece — como estado, ciclo de vida, context e refs. Eles não mudam fundamentalmente como o React funciona e seu conhecimento de componentes, props e fluxo de dados de cima para baixo continua relevante.
Hooks tem sua curva de aprendizado. Se tiver algo faltando nessa documentação, abra um issue e nós vamos tentar ajudar.
Devo usar Hooks, classes ou um misto dos dois?
Quando você estiver pronto, encorajamos você a começar usando Hooks em novos componentes que você escrever. Tenha certeza que todos no seu time estão de acordo em usá-los e estão familiarizados com a documentação. Nós não recomendamos reescrever suas classes existentes para Hooks a menos que você tenha planejado reescrevê-las previamente (por exemplo, para arrumar bugs).
Você não pode usar Hooks dentro de um componente classe, mas você definitivamente pode misturar classes e funções com Hooks em uma única árvore. Se um componente é uma classe ou uma função que usa Hooks é um detalhe de implementação daquele componente. A longo prazo, nós esperamos que Hooks sejam a principal maneira que as pessoas escrevam componentes React.
Hooks cobrem todos os casos de uso para classes?
Nosso objetivo é que Hooks cubra todos os casos de uso o mais rápido possível. Ainda não há Hook equivalente para os ciclos de vida getSnapshotBeforeUpdate, getDerivedStateFromError e componentDidCatch, que são mais incomuns, mas planejamos adiciona-los em breve.
Hooks substituem render props e HOC (componente de alta-ordem, do inglês high-order component)?
Frequentemente, render props e HOC renderizam somente um filho. Nós achamos que Hooks são uma maneira mais simples de atender esse caso de uso. Ainda existe lugar para ambos os padrões (por exemplo, um componente de scroll virtual talvez tenha uma prop renderItem, ou um container visual talvez tenha sua própria estrutura DOM). Mas na maioria dos casos, Hooks serão suficiente e podem ajudar a reduzir o aninhamento na sua árvore.
O que Hooks significam para APIs populares como o connect() do Redux e o React Router?
Você pode continuar a usar exatamente as mesmas APIs que sempre usou; elas vão continuar funcionando.
React Redux desde a v7.1.0 suporta Hooks API e expõe hooks como useDispatch ou useSelector.
React Router suporta hooks desde a v5.1.
Outras bibliotecas também podem suportar hooks no futuro.
Hooks funcionam com tipagem estática?
Hooks foram planejados com tipagem estática em mente. Como eles são funções, eles são mais fáceis de tipar corretamente do que padrões como high-order components. As últimas definições do React para Flow e Typescript incluem suporte para React Hooks.
Importante observar, que Hooks customizados te dão o poder de restringir a API do React se você quiser usa-la de alguma maneira mais rigorosa. React te dá as primitivas mas você pode combina-las de diferentes maneiras além das que fornecemos.
Como testar componentes que usam Hooks?
Do ponto de vista do React, um componente usando Hooks é somente um componente regular. Se sua solução para testes não depende do funcionamento interno do React, testar componentes com Hooks não deveria ser diferente de como você normalmente testa componentes.
Nota
Em Testing Recipes tem muitos exemplos que você pode copiar e colar.
Por exemplo, digamos que temos este componente contador:
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}Nós vamos testa-lo usando React DOM. Para garantir que o comportamento corresponde ao que acontece no browser, nós vamos envolver o código que renderiza e atualiza com ReactTestUtils.act():
import React from 'react';
import ReactDOM from 'react-dom/client';
import { act } from 'react-dom/test-utils';import Counter from './Counter';
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
container = null;
});
it('can render and update a counter', () => {
// Testa a primeira renderização e efeito
act(() => { ReactDOM.createRoot(container).render(<Counter />); }); const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');
// Testa segunda renderização e efeito
act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});As chamadas para act() também vão descarregar os efeitos dentro dele.
Se você precisa testar um Hook customizado, você pode faze-lo criando um componente no seu teste e usando o seu Hook nele. Então você pode testar o componente que escreveu.
Para reduzir o boilerplate, nós recomendamos usar React Testing Library que é projetada para incentivar a escrever testes que usam seus componentes como usuários finais usam.
Para mais informações, confira Testing Recipes.
O que exatamente as regras de lint impõem?
Nós fornecems um plugin ESLint que impõem regras de Hooks para evitar bugs. Elas assumem que qualquer função começando com ”use” e uma letra maiúscula em segunda é um Hook. Nós reconhecemos que esta heurística não é perfeita e que talvez aconteçam alguns falso positivos mas sem uma convenção simplesmente não há como fazer Hooks funcionarem bem — e nomes mais longos iriam desencorajar pessoas tanto de adotar Hooks ou de seguir a convenção.
Em particular, a regra impõe que:
- Chamadas para Hooks ocorrem ou dentro de uma função usando
PascalCase(tratada como componente) ou dentro de outra funçãouseSomething(tratada como um Hook customizado). - Hooks são chamados na mesma ordem em toda renderização.
Existem mais algumas heurísticas e talvez elas mudem ao longo do tempo conforme nós regulamos as regras para balancear entre encontrar bugs e evitar falsos positivos.
De Classes para Hooks
Como os métodos de ciclo de vida correspondem aos Hooks?
constructor: Funções não precisam de um constructor. Você pode inicializar o estado com ouseState. Se calcular o estado for custoso, você pode passar uma função para ouseState.getDerivedStateFromProps: Não é necessário, agende um update enquanto estiver renderizando.shouldComponentUpdate: VejaReact.memoabaixo.render: Este é o próprio corpo da função.componentDidMount,componentDidUpdate,componentWillUnmount: O HookuseEffectpode expressar todas as combinações desses, (incluindo casos menos comuns).getSnapshotBeforeUpdate,componentDidCatchegetDerivedStateFromError: Não há Hooks equivalentes para esses métodos ainda, mas eles serão adicionados em breve.
Como posso fazer a busca de dados com Hooks?
Aqui está uma pequena demonstração para você começar. Para saber mais, confira o artigo sobre a obtenção de dados com Hooks.
Existe algo como variáveis de instância?
Sim! O Hook useRef() não é somente para DOM. O objeto “ref” é um container genérico no qual a propriedade current é mutável e pode conter qualquer valor, similar a uma propriedade de instância de uma classe.
Você pode escrever nele de dentro do useEffect:
function Timer() {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
// ...
});
intervalRef.current = id; return () => {
clearInterval(intervalRef.current);
};
});
// ...
}Se nós só quiséssemos criar um intervalo, não precisaríamos de ref (id poderia ser local do efeito), mas é útil se quisermos limpar o intervalo usando um manipulador de eventos:
// ...
function handleCancelClick() {
clearInterval(intervalRef.current); }
// ...Conceitualmente, você pode pensar em refs como similares a variávels de instância em uma classe. A menos que você esteja fazendo inicialização lazy, evite definir refs durante a renderização — isso pode levar a comportamentos inesperados. Ao invés disso, normalmente você deseja modificar as refs nos manipuladores de eventos e efeitos.
Devo usar uma ou muitas variáveis de estado?
Se você está vindo de classes, você pode ser tentado a sempre chamar useState() uma vez e por todo o estado em um único objeto. Você pode fazer isso se quiser. Aqui segue um exemplo de um componente que segue o movimento do mouse. Nós guardamos sua posição e tamanho no estado local:
function Box() {
const [state, setState] = useState({ left: 0, top: 0, width: 100, height: 100 });
// ...
}Agora vamos dizer que queremos escrever uma lógica que muda left e top quando o usuário move o seu mouse. Note que nós temos que mesclar esses campos no estado anterior manualmente:
// ...
useEffect(() => {
function handleWindowMouseMove(e) {
// Espalhando "...state" garante que width e height não se "percam" setState(state => ({ ...state, left: e.pageX, top: e.pageY })); }
// Nota: essa implementação é um pouco simplificada
window.addEventListener('mousemove', handleWindowMouseMove);
return () => window.removeEventListener('mousemove', handleWindowMouseMove);
}, []);
// ...Isto é porque quando atualizamos uma variável de estado, nós substituimos seu valor. É diferente de this.setState em uma classe, que mescla os campos atualizados no objeto.
Se você sente falta da mesclagem automática, você poderia escrever um Hook customizado, useLegacyState, que mescla o update no objeto. No entanto, nós recomendamos dividir o estado em múltiplas variáveis de estado baseado nos valores que tendem a mudar juntos.
Por exemplo, poderíamos dividir nosso componente em position e size e sempre substituir position sem a necessidade de mesclar:
function Box() {
const [position, setPosition] = useState({ left: 0, top: 0 }); const [size, setSize] = useState({ width: 100, height: 100 });
useEffect(() => {
function handleWindowMouseMove(e) {
setPosition({ left: e.pageX, top: e.pageY }); }
// ...Separar o estado em variáveis independentes também tem outro benefício. Torna mais fácil para extrair uma lógica relacionada para um Hook customizado posteriormente, como por exemplo:
function Box() {
const position = useWindowPosition(); const [size, setSize] = useState({ width: 100, height: 100 });
// ...
}
function useWindowPosition() { const [position, setPosition] = useState({ left: 0, top: 0 });
useEffect(() => {
// ...
}, []);
return position;
}Note como nós conseguimos mover a chamada useState da variável de estado position e o efeito relacionado para um Hook customizado sem alterar o seu código. Se todo o estado estivesse em um único objeto, extrair seria mais difícil.
Tanto colocar todo estado em um único useState e usar múltiplos useState para cada campo pode funcionar. Componentes tendem a ser mais legíveis quando você encontra um balanço entre esses dois extremos e agrupa estados relacionados em algunas variáveis de estado independentes. Se a lógica do estado se torna muito complexa, nós recomendamos gerenciá-la com um reducer ou com um Hook customizado.
Posso usar um efeito somente em updates?
Esse é um caso de uso raro. Se você precisar, você pode usar uma ref mutável para manualmente armazenar um valor boleano correspondente a se você está no primeiro render ou num subsequente, usando então essa flag no seu efeito. (Se você se encontrar fazendo isso regularmente, pode criar um Hook customizado pra isso.)
Como acessar as props ou o estado anterior?
Existem dois casos em que você pode querer obter adereços ou estados anteriores.
Às vezes, você precisa de props anteriores para limpar um efeito. Por exemplo, você pode ter um efeito que se inscreve em um soquete baseado no prop userId. Se a propriedade userId mudar, você deseja cancelar a assinatura do anterior userId e assinar o próximo. Você não precisa fazer nada de especial para que isso funcione:
useEffect(() => {
ChatAPI.subscribeToSocket(props.userId);
return () => ChatAPI.unsubscribeFromSocket(props.userId);
}, [props.userId]);No exemplo acima, se userId mudar de 3 para 4, ChatAPI.unsubscribeFromSocket(3) será executado primeiro e, em seguida, ChatAPI.subscribeToSocket(4) será executado. Não há necessidade de obter o userId “anterior” porque a função de limpeza irá capturá-lo em um fechamento.
Outras vezes, pode ser necessário ajustar o estado com base em uma alteração nos adereços ou outro estado. Isso raramente é necessário e geralmente é um sinal de que você tem algum estado duplicado ou redundante. No entanto, no caso raro de precisar desse padrão, você pode armazenar o estado anterior ou props no estado e atualizá-los durante a renderização.
Sugerimos anteriormente um Hook personalizado chamado usePrevious para manter o valor anterior. No entanto, descobrimos que a maioria dos casos de uso se enquadra nos dois padrões descritos acima. Se o seu caso de uso for diferente, você pode manter um valor em uma referência e atualizá-lo manualmente quando necessário. Evite ler e atualizar as referências durante a renderização porque isso dificulta a previsão e o entendimento do comportamento do seu componente.
Por que estou vendo props obsoletos ou state dentro da minha função?
Qualquer função dentro de um componente, incluindo manipuladores de eventos e efeitos, “vê” as props e o state da renderização em que foi criado. Por exemplo, considere este código:
function Example() {
const [count, setCount] = useState(0);
function handleAlertClick() {
setTimeout(() => {
alert('Você clicou: ' + count);
}, 3000);
}
return (
<div>
<p>