Práticas recomendadas com ganchos React

Publicados: 2022-03-10
Resumo rápido ↬ Este artigo aborda as regras do React Hooks e como começar a usá-los efetivamente em seus projetos. Observe que, para seguir este artigo em detalhes, você precisará saber como usar React Hooks.

React Hooks são uma nova adição no React 16.8 que permite usar state e outros recursos do React sem escrever um componente de class . Em outras palavras, Hooks são funções que permitem que você “se conecte” a recursos de estado e ciclo de vida do React a partir de componentes de função. (Eles não funcionam dentro de componentes class .)

O React fornece alguns Hooks embutidos como useState . Você também pode criar seus próprios Hooks para reutilizar o comportamento stateful entre diferentes componentes. O exemplo abaixo mostra um contador cujo estado é gerenciado usando o gancho useState() . Cada vez que você clica no botão, usamos setCount() para atualizar o valor de count em 1 .

Veja o Pen [exemplo React Hook with Counter](https://codepen.io/smashingmag/pen/QWbXMyM) de Adeneye Abiodun David.

Veja o exemplo Pen React Hook com Counter por Adeneye Abiodun David.

Este exemplo renderiza um contador com valor 0 . Quando você clica no botão, ele incrementa o valor em 1 . O valor inicial do componente é definido usando useState .

 const [count, setCount] = useState(0)

Como você pode ver, definimos isso como 0 . Em seguida, usamos o método onClick() para chamar setCount quando queremos incrementar o valor.

 <button onClick={() => setCount(count + 1)}> Click me </button>

Antes do lançamento do React Hooks, este exemplo teria usado mais linhas de código, pois teríamos que usar um componente de class .

Mais depois do salto! Continue lendo abaixo ↓

Regras de Hooks React

Antes de nos aprofundarmos nas melhores práticas, precisamos entender as regras dos React Hooks que também são alguns dos conceitos fundamentais das práticas apresentadas neste artigo.

React Hooks são funções JavaScript, mas você precisa seguir duas regras ao usá-los.

  1. Ganchos de chamada no nível superior;
  2. Apenas chame Hooks de componentes React.

Nota : Essas duas regras foram introduzidas no React Hooks, ao invés de fazerem parte do próprio JavaScript.

Vejamos essas regras com mais detalhes.

Ganchos de chamada no nível superior

Não chame Hooks dentro de loops, condições ou funções aninhadas. Sempre use Hooks no nível superior de sua função React. Seguindo essa regra, você garante que os Hooks sejam chamados na mesma ordem toda vez que um componente for renderizado. É isso que permite que o React preserve corretamente o estado dos Hooks entre várias chamadas de useState e useEffect .

Vamos fazer um componente Form que terá dois estados:

  • accountName
  • accountDetail

Esses estados terão valores padrão, usaremos o gancho useEffect para persistir o estado no armazenamento local do nosso navegador ou no título do nosso documento.

Agora, esse componente talvez gerencie com sucesso seu estado se permanecer o mesmo entre várias chamadas de useState e useEffect .

 function Form() { // 1. Use the accountName state variable const [accountName, setAccountName] = useState('David'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); // 3. Use the accountDetail state variable const [accountDetail, setAccountDetail] = useState('Active'); // 4. Use an effect for updating the title useEffect(function updateStatus() { document.title = accountName + ' ' + accountDetail; }); // ... }

Se a ordem dos nossos Hooks mudar (o que pode ser possível quando eles são chamados em loops ou condicionais), o React terá dificuldade em descobrir como preservar o estado do nosso componente.

 // ------------ useState('David') // 1. Initialize the accountName state variable with 'David' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Active') // 3. Initialize the accountdetail state variable with 'Active' useEffect(updateStatus) // 4. Add an effect for updating the status // ------------- // Second render // ------------- useState('David') // 1. Read the accountName state variable (argument is ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Active') // 3. Read the accountDetail state variable (argument is ignored) useEffect(updateStatus) // 4. Replace the effect for updating the status // ...

Essa é a ordem que o React segue para chamar nossos hooks. Como a ordem permanece a mesma, ela poderá preservar o estado do nosso componente. Mas o que acontece se colocarmos uma chamada Hook dentro de uma condição?

 // We're breaking the first rule by using a Hook in a condition if (accountName !== '') { useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); }

A accountName !== '' é true na primeira renderização, então executamos este Hook. No entanto, na próxima renderização, o usuário pode limpar o formulário, tornando a condição false . Agora que pulamos esse Hook durante a renderização, a ordem das chamadas do Hook se torna diferente:

 useState('David') // 1. Read the accountName state variable (argument is ignored) // useEffect(persistForm) // This Hook was skipped! useState('Active') // 2 (but was 3). Fail to read the accountDetails state variable useEffect(updateStatus) // 3 (but was 4). Fail to replace the effect

O React não saberia o que retornar para a segunda chamada do Hook useState . O React esperava que a segunda chamada de Hook neste componente correspondesse ao efeito persistForm , assim como durante a renderização anterior — mas não corresponde mais. Daquele ponto em diante, cada próxima chamada de Hook após a que pulámos também mudaria em um – levando a bugs.

É por isso que Hooks devem ser chamados no nível superior de nossos componentes. Se quisermos executar um efeito condicionalmente, podemos colocar essa condição dentro do nosso Hook.

Nota : Confira os documentos do React Hook para ler mais sobre este tópico.

Apenas Chame Hooks de Componentes React

Não chame Hooks de funções JavaScript regulares. Em vez disso, você pode chamar Hooks dos componentes da função React. Vamos dar uma olhada na diferença entre a função JavaScript e o componente React abaixo:

Função JavaScript

 import { useState } = "react"; function toCelsius(fahrenheit) { const [name, setName] = useState("David"); return (5/9) * (fahrenheit-32); } document.getElementById("demo").innerHTML = toCelsius;

Aqui importamos o hook useState do pacote React e declaramos nossa função. Mas isso é inválido, pois não é um componente React.

Função Reagir

 import React, { useState} from "react"; import ReactDOM from "react-dom"; function Account(props) { const [name, setName] = useState("David"); return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p> } ReactDom.render( <Account total={20} amount={5000} />, document.getElementById('root') );

Mesmo que o corpo de ambos pareça semelhante, o último se torna um componente quando importamos o React para o arquivo. Isso é o que nos possibilita usar coisas como ganchos JSX e React dentro.

Se você importou seu hook preferido sem importar o React (o que o torna uma função regular), você não poderá usar o Hook que você importou, pois o Hook é acessível apenas no componente React.

Ganchos de chamada de ganchos personalizados

Um Hook customizado é uma função JavaScript cujo nome começa com use e que pode chamar outros Hooks. Por exemplo, useUserName é usado abaixo de um Gancho personalizado que chama os ganchos useState e useEffect . Ele busca dados de uma API, percorre os dados e chama setIsPresent() se o nome de usuário específico recebido estiver presente nos dados da API.

 export default function useUserName(userName) { const [isPresent, setIsPresent] = useState(false); useEffect(() => { const data = MockedApi.fetchData(); data.then((res) => { res.forEach((e) => { if (e.name === userName) { setIsPresent(true); } }); }); }); return isPresent; }

Podemos, então, reutilizar a funcionalidade desse gancho em outros lugares onde precisamos disso em nosso aplicativo. Nesses lugares, exceto quando necessário, não precisamos mais chamar useState ou useEffect .

Ao seguir essa regra, você garante que toda a lógica com estado em um componente seja claramente visível em seu código-fonte.

Plugin ESLint

O plugin ESLint chamado eslint-plugin-react-hooks reforça as regras acima. Isso é útil para aplicar as regras ao trabalhar em um projeto. Eu sugiro que você use este plugin ao trabalhar em seu projeto, especialmente ao trabalhar com outras pessoas. Você pode adicionar este plugin ao seu projeto se quiser experimentá-lo:

 // Your ESLint configuration { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }

Este plugin é incluído por padrão no Create React App. Portanto, você não precisa adicioná-lo se inicializar seus aplicativos React usando Create-React-App.

Pensando em ganchos

Vamos dar uma breve olhada nos componentes de class e componentes funcionais (com Hooks), antes de mergulhar nas poucas práticas recomendadas de Hooks.

A maneira mais simples de definir um componente no React é escrever uma função JavaScript que retorne um elemento React:

 function Welcome(props) { return <h1>Hello, {props.name}</h1>; }

O componente Welcome aceita props que é um objeto que contém dados e retorna um elemento React. Podemos então importar e renderizar este componente em outro componente.

O componente class usa uma metodologia de programação chamada Encapsulation , que basicamente significa que tudo o que for relevante para o componente de classe viverá dentro dele. Métodos de ciclo de vida ( constructors , componentDidMount() , render e assim por diante) fornecem aos componentes uma estrutura previsível.

O encapsulamento é um dos fundamentos da OOP (Programação Orientada a Objetos). Refere-se ao agrupamento de dados dentro dos métodos que operam nesses dados e é usado para ocultar os valores ou o estado de um objeto de dados estruturados dentro de uma classe - impedindo o acesso direto de partes não autorizadas a eles.

Com Hooks, a composição de um componente muda de uma combinação de Hooks de ciclo de vida — para funcionalidades com alguma renderização no final.

Componente de função

O exemplo abaixo mostra como Hooks personalizados podem ser usados ​​em um componente funcional (sem mostrar qual é o corpo). No entanto, o que ele faz ou pode fazer não é limitado. Pode ser instanciar variáveis ​​de estado, consumir contextos, inscrever o componente em vários efeitos colaterais — ou todos os itens acima, se você estiver usando um gancho personalizado!

 function { useHook{...}; useHook{...}; useHook{...}; return (
...
); }

Componente de classe

Um componente class requer que você estenda de React.Component e crie uma função de render que retorne um elemento React. Isso requer mais código, mas também lhe dará alguns benefícios.

 class { constructor(props) {...} componentDidMount() {...} componentWillUnmount() {...} render() {...} }

Existem alguns benefícios que você obtém usando componentes funcionais no React:

  1. Ficará mais fácil separar componentes de contêiner e de apresentação porque você precisa pensar mais sobre o estado do seu componente se não tiver acesso a setState() em seu componente.
  2. Os componentes funcionais são muito mais fáceis de ler e testar porque são funções JavaScript simples sem estado ou ganchos de ciclo de vida.
  3. Você acaba com menos código.
  4. A equipe do React mencionou que pode haver um aumento de desempenho para componentes funcionais em futuras versões do React.

Isso leva à primeira prática recomendada ao usar React Hooks.

Práticas recomendadas de ganchos

1. Simplifique seus ganchos

Manter React Hooks simples lhe dará o poder de controlar e manipular efetivamente o que acontece em um componente ao longo de sua vida útil. Evite escrever Hooks personalizados tanto quanto possível ; você pode inline um useState() ou useEffect() em vez de criar seu próprio gancho.

Se você estiver usando um monte de Hooks customizados que estão relacionados em funcionalidade, você pode criar um hook customizado que atue como um wrapper para eles. Vamos dar uma olhada em dois componentes funcionais diferentes com ganchos abaixo.

Componente Funcional v1

 function { useHook(...); useHook(...); useHook(...); return( <div>...</div> ); }

Componente Funcional v2

 function { useCustomHook(...); useHook(...); useHook(...); return( <div>...</div> ); }

v2 é uma versão melhor porque mantém o gancho simples e todos os outros useHook s são alinhados de acordo. Isso nos permite criar funcionalidades que podem ser reutilizadas em diferentes componentes e também nos dá mais poder para controlar e manipular nossos componentes de forma eficaz. Em vez de adotar a v1 na qual nossos componentes estão cheios de Hooks, você deve usar a v2, que facilitará a depuração e seu código ficará mais limpo.

2. Organize e estruture seus ganchos

Uma das vantagens do React Hooks é a capacidade de escrever menos código que seja fácil de ler. Em alguns casos, a quantidade de useEffect() e useState() ainda pode ser confusa. Quando você mantém seu componente organizado, isso ajuda na legibilidade e mantém o fluxo de seus componentes consistente e previsível. Se seus Hooks personalizados forem muito complicados, você sempre poderá dividi-los em Hooks subpersonalizados. Extraia a lógica do seu componente para Hooks personalizados para tornar seu código legível.

3. Use snippets de ganchos de reação

React Hooks Snippets é uma extensão do Visual Studio Code para tornar os React Hooks mais fáceis e rápidos. Atualmente, cinco ganchos são suportados:

  • useState()
  • useEffect()
  • useContext()
  • useCallback()
  • useMemo()

Outros trechos também foram adicionados. Eu tentei trabalhar com esses Hooks e foi uma das melhores práticas que usei pessoalmente enquanto trabalhava com eles.

Existem duas maneiras de adicionar snippets React Hooks ao seu projeto:

  1. Comando
    Inicie o VS Code Quick open ( Ctrl + P ), cole ext install ALDuncanson.react-hooks-snippets e pressione Enter .
  2. Mercado de extensão
    Inicie o 'VS Code Extension Marketplace' ( Ctrl + Shift + X ) e procure por 'React Hook Snippets'. Em seguida, procure o ícone 'Alduncanson'.

Recomendo o primeiro trecho. Leia mais sobre os snippets aqui ou verifique os últimos snippets de Hooks aqui.

4. Considere as Regras dos Ganchos

Esforce-se para sempre levar em consideração as duas regras de Hooks que aprendemos anteriormente ao trabalhar com React Hooks.

  • Chame seus Hooks apenas no nível superior. Não chame Hooks dentro de loops, condições ou funções aninhadas.
  • Sempre chame Hooks de componentes de função React ou de Hooks personalizados, não chame Hooks de funções JavaScript regulares.

O plugin ESlint chamado eslint-plugin-react-hooks aplica essas duas regras, você pode adicionar este plugin ao seu projeto se quiser, como explicamos acima na seção de regras de ganchos.

As melhores práticas não foram totalmente resolvidas porque os Hooks ainda são relativamente novos. Portanto, a adoção deve ser tomada com a precaução que se tomaria ao adotar qualquer tecnologia inicial. Com isso em mente, Hooks são o caminho para o futuro do React.

Conclusão

Espero que tenham gostado deste tutorial. Aprendemos as duas regras mais importantes do React Hooks e como pensar efetivamente em Hooks. Analisamos componentes funcionais e algumas práticas recomendadas para escrever Hooks da maneira correta e eficaz. Por mais breves que sejam as regras, é importante torná-las sua bússola ao escrever regras. Se você está propenso a esquecê-lo, você pode usar o plug-in ESLint para aplicá-lo.

Espero que você aproveite todas as lições aprendidas aqui em seu próximo projeto React. Boa sorte!

Recursos

  • “Introduzindo Hooks,” React Docs
  • “Componentes funcionais versus de classe no React”, David Joch, Medium
  • “Mixins considerados prejudiciais”, Dan Abramov, React Blog
  • “React Hooks: Best Practices and A Shift In Mindset”, Bryan Manuele, Medium
  • “React Hooks Snippets For VS Code,” Anthony Davis, Visual Code Marketplace