Um olhar mais profundo sobre os ganchos React mais populares
Pawel Rybczynski
Software Engineer
No decurso de muitas entrevistas, reparei que mesmo os programadores experientes têm dificuldade em distinguir os Hooks, já para não falar das suas capacidades mais avançadas. Por isso, vou tentar explicar neste artigo como os Hooks devem ser usados.
Os aspectos mais importantes a ter em conta sobre os ganchos:
só podem ser utilizados em componentes de função - os componentes de classe têm a sua própria implementação do ciclo de vida;
começam sempre por utilização;
pode utilizar os Hooks que quiser, mas não se esqueça de que a sua utilização tem um impacto no desempenho geral;
têm de ser executados pela mesma ordem em cada renderização... mas porquê? Vamos dar uma olhada em um exemplo:
<code>srcFunctionComponent.js
Linha 11:5: React O gancho "useEffect" é chamado condicionalmente. <strong>Ganchos React</strong> devem ser chamados exatamente na mesma ordem em cada componente render .eslintreact-hooks/rules-of-hooks
Como pode ver, é apenas um aviso do eslint, pelo que pode desactivá-lo adicionando um comando a partir de baixo no topo do ficheiro FunçãoComponente
/* eslint-disable react-hooks/rules-of-hooks */
e vai funcionar, mas só até cumprirmos a condição que executa o nosso Hook. A próxima coisa que veremos é este erro.
Erro não detectado: Renderizou mais ganchos do que na renderização anterior.
React 5
FunctionComponent FunctionComponent.js:11
React 12
unstable_runWithPriority scheduler.development.js:468
React 17
js index.js:7
js main.chunk.js:905
Webpack 7
react-dom.development.js:15162
Por que isso acontece? O React se baseia na ordem em que os Hooks são chamados, pois o React não saberia o que retornar para o useEffect porque não havia tal Hook na linha para verificar.
Lembre-se, o eslint é uma ferramenta poderosa, que ajuda nós captura muitos erros e bugs potenciais. Desativar os avisos é perigoso. Verifique sempre se ignorar o aviso pode causar uma falha na aplicação.
useState
Provavelmente já sabes como é que fica 😉
const [value, setValue] = useState(0);
Assim, tem 4 elementos: estado (valor reativo), função de atualização (setter), gancho real (função) e valor inicial opcional. Porque é que retorna um array? Porque podemos reestruturá-lo como quisermos.
Agora quero concentrar-me no último elemento - o valor inicial. Há duas maneiras de passar o estado inicial:
Por um valor codificado ou algo do género - que será chamado em cada renderização
const [value, setValue] = useState(0);
Por uma versão de função. É realmente útil se quisermos executar o estado inicial apenas uma vez, na primeira renderização. Talvez seja necessário fazer muitos cálculos complexos para receber o estado inicial? Isso vai diminuir bastante o custo de recursos, yay!
Outra coisa que pode criar erros no fluxo da aplicação: provavelmente sabe como atualizar um estado, certo?
setValue(1);
Certo... mas e se eu quiser atualizar o estado com base num estado anterior?
setValue(value + 1);
Sim... Mas não... E se tentar chamar a função setter duas vezes, uma após a outra? A forma recomendada de atualizar um estado com base no estado anterior é utilizar uma função. Esta garante que se está a referir ao estado anterior
Este Hook recebe 2 argumentos (o segundo é opcional) e usamo-lo para lidar com efeitos secundários. E dependendo do que passarmos como segundo argumento, o Hook será chamado de forma diferente:
sem segundo argumento - cada renderização
useEffect(() => {
doSomething();
});
matriz vazia - apenas na primeira apresentação
useEffect(() => {
doSomething();
}, []);
matriz com dependências - sempre que o valor na matriz de dependências muda
Com o useEffect, podemos utilizar algo a que chamamos limpeza. Para que é que serve? É muito útil, mas acho que é melhor para limpar ouvintes de eventos. Digamos que você queira criar um event listener que depende de algum estado. Você não quer adicionar um novo event listener a cada mudança de estado, porque depois de algumas renderizações haverá tantos listeners que isso afetará o desempenho da aplicação. Uma ótima maneira de evitar essas coisas é usar o recurso de limpeza. Como fazer isso? Basta adicionar uma função de retorno ao useEffect.
Porque está dentro do Hook useEffect, o retorno é chamado dependendo do array de dependências - em cada renderização, apenas na primeira renderização, ou quando o valor no array de dependências muda. Mas quando o componente é desmontado, cleaning será chamado no segundo argumento, não importa o que aconteça. O retorno código é chamado antes do código real do Hook. É muito lógico - primeiro limpar o antigo, depois criar um novo. Certo?
No início, parece estar tudo bem. Está a obter alguns dados e, quando os dados chegam, actualiza o estado. E aqui está a armadilha:
Por vezes, recebe um aviso deste tipo: Não é possível efetuar uma atualização de estado do React num componente não montado. Isto não é uma opção, mas indica uma fuga de memória na sua aplicação. Para corrigir, cancele todas as assinaturas e tarefas assíncronas em uma função de limpeza useEffect.
A razão é que o componente pode ser desmontado entretanto, mas a aplicação continuará a tentar atualizar o estado desse componente depois de a promessa ter sido cumprida. Como lidar com isso? É necessário verificar se o componente existe.
Nota: Existe um Hook muito semelhante => useLayoutEffect() - a chamada de retorno é executada após a renderização do componente, mas antes de o dom ser atualizado visualmente. É útil quando se trabalha com getBoundingClientRect(), mas deve usar useEffect por defeito. Porquê? Porque pode bloquear as actualizações visuais - quando tem um código complexo dentro do seu efeito Hook.
useContext
Para que serve? Partilhar dados sem passar props. É composto pelos seguintes elementos:
Contexto criado - dados
Fornecedor de contexto - fornecer contexto a todas as crianças
Em child, é necessário importar o contexto e chamar o Hook useContext e passar esse contexto como argumento.
importar { UserContext } de "./App";
const { name } = useContext(UserContext);
retornar <h1>Olá {nome}<>
```
Voilà. Parece fixe. Principalmente para passar dados globais como temas, etc. Não recomendado para uso em tarefas com mudanças muito dinâmicas.
É claro que podemos criar um provedor de contexto personalizado e um Hook personalizado para reduzir o boilerplate... mas tratarei dos Hooks personalizados no próximo artigo.
useReducer
Permite-nos gerir o estado e voltar a renderizar quando o estado muda - como useState. É semelhante ao redução reducer. Este é melhor do que useState quando a lógica de estado é mais complicada.
Quando a utilizar? Quando queremos obter igualdade referencial (reduzindo assim o número de funções criadas). Este Hook devolve a função, ao contrário de useMemo que devolve o valor.
Exemplo: Criar uma função no componente principal e depois passá-la através de props
Ele será registado na consola em cada renderização! Mesmo que os valores dentro do getSquaredValue() não foi alterada. Mas podemos evitar isso envolvendo essa função em useCallback
Não é neutro quando se olha para os custos dos recursos - useMemo deve ser chamado em cada renderização, guarda o valor na memória e compara (sobrecarga de memória),
utiliza Memoization - a técnica de otimização, forma específica de caching.
Deve ser utilizado apenas em 2 cenários:
Se quiser evitar chamar um código complexo em cada processamento;
Se pretender obter uma igualdade referencial.
Vamos ver um pouco mais de perto o segundo caso. Queremos usar useEffect com um objeto como dependência. Como os objetos são comparados por sua referência, useEffect será chamado em cada renderização. Para evitar isso, podemos combinar useEffect com useMemo para memorizar esses objetos e então passar esses objetos memorizados para o array de dependências. Um pequeno exemplo:
O objeto 'hobbit' faz com que as dependências do gancho useEffect (linha 49) mudem em cada renderização. Mova-o para dentro do retorno de chamada useEffect. Em alternativa, envolva a inicialização de 'hobbit' no seu próprio Gancho useMemo ().eslintreact-hooks/exhaustive-deps
A coisa mais importante: useRef não desencadeia a re-renderização (como useState) porque não está ligado ao ciclo de renderização - mantém a mesma referência entre renders.
const ref = useRef(0);
Para chamar o valor guardado, é necessário utilizar uma propriedade atual (ref é um objeto) - ref.atual
O segundo caso para o qual podemos usar esse Hook é para referenciar elementos dentro do HTML. Cada elemento tem um atributo ref. Assim, podemos lidar com foco, eventos etc.
O terceiro caso é que podemos utilizar refs para lidar com componentes não controlados. Pode ler mais sobre eles em documentos react, mas, resumidamente, é assim:
Como pode ver, não há nenhum manipulador de eventos, ele apenas se lembra do valor digitado. É ótimo para lidar com formulários básicos quando apenas se pretende ler os valores guardados quando se precisa deles (como quando se submete).
Bónus: É ótimo quando é necessário recordar valores de estados anteriores. Você pode usar para isso o Hook useEffect, basta passar o estado para o ref.
Como pode ver, os Hooks não são assim tão óbvios. Podemos combiná-los para resolver muitos problemas. O estudo deste tema vai certamente trazer-lhe grandes benefícios.
E há também ganchos personalizados...
Em conclusão, Ganchos React revolucionaram a forma como Desenvolvedores React abordagem de construção aplicações web . Ao proporcionar uma forma mais intuitiva e eficiente de gerir o estado e o ciclo de vida dos componentes funcionais, os hooks tornaram-se parte integrante da Desenvolvimento do React.
Quer seja um programador experiente ou esteja apenas a começar com o React, é crucial compreender os hooks mais populares e os seus casos de utilização. Com ganchos como useState, useEffect, useContext, e mais, Componentes do React pode ser construído com um código mais limpo e reutilizável. Além disso, a capacidade de criar ganchos personalizados permite que os programadores encapsulem e partilhem a lógica entre vários componentes, promovendo a reutilização e a modularidade do código. À medida que o React continua a evoluir e a introduzir novas funcionalidades, os hooks desempenharão, sem dúvida, um papel central no aproveitamento de todo o potencial da estrutura.
Assim, quer esteja a trabalhar numa pequena aplicação funcional ou numa aplicação Web de grande escala, abraçar Ganchos React irá melhorar o seu fluxo de trabalho de desenvolvimento e desbloquear uma infinidade de possibilidades para criar aplicações robustas e ricas em funcionalidades Aplicações React .