Lançado pela primeira vez em outubro de 2018, as APIs de react hooks fornecem uma alternativa para escrever componentes baseados em classe e oferecem uma abordagem alternativa para gerenciamento de estado e métodos de ciclo de vida. Os hooks trazem para os componentes funcionais as coisas que antes só podíamos fazer com as classes, como ser capaz de trabalhar com o estado local React, efeitos e contexto por meio de useState, useEffecte useContext.

A maneira mais fácil de descrever os  Hooks é mostrar exemplos lado a lado, a partir de um componente de classe que precisa ter acesso aos métodos de estado e ciclo de vida e outro exemplo em que obtemos o mesmo efeito com um componente funcional.

Dessa forma, os Hooks trazem muitos benefícios para nós como desenvolvedores e desenvolvedoras, além de mudar para melhor a maneira como escrevemos componentes. 

A seguir, forneceremos um exemplo de trabalho semelhante aos dos documentos do ReactJS, com uma demonstração para cada estágio de nosso aprendizado. Então, vamos começar a aprender sobre React Hooks.

Acompanhe:

O que são Hooks?

Metaforicamente falando, os Hooks cortam a gordura. Isso significa que eles reduzem e tornam nosso código mais legível, conciso e objetivo. Para demonstrar, vamos verificar uma versão de classe de nosso “efeito de título de documento” canônico e ver a diferença entre como costumávamos escrever algo assim lado a lado com um exemplo usando um Hook instalado por npm que faz a mesma coisa.

O exemplo abaixo mostra como o componente perdeu um pouco de peso. Não apenas economizamos cerca de cinco linhas de código, mas a legibilidade e a capacidade de teste também melhoraram com a mudança para Hooks. 

Assim, mudar o código existente para Hooks pode ter um grande impacto no grande volume de código e legibilidade. Porém, lembre-se de que o Hooks é compatível com as versões anteriores do código que está substituindo e pode conviver com ele, portanto, não há necessidade de reescrever toda a base de código imediatamente.

Antes:



import React from 'react';

class Counter extends React.Component {
  constructor() {
    this.state = { count: 0 };
    this.incrementCount = this.incrementCount.bind(this);
  }
  incrementCount() {
    this.setState({ count: this.state.count + 1 });
  }
 
  componentDidMount() { document.title = `Você clicou ${this.state.count} vezes`; }
  componentDidUpdate() { document.title = `Você clicou ${this.state.count} vezes`; }

  render() {
    return (
      <div>
        <p>Você clicou {this.state.count} vezes</p>
        <button onClick={this.incrementCount}>Clique Aqui</button>
      </div>
    );
  }
}

export default Counter;

Depois:



import React, { Component, useState } from 'react';
import useDocumentTitle from '@rehooks/document-title';

function Counter() {
  const [count, setCount] = useState(0);
  const incrementCount = () => setCount(count + 1);
  useDocumentTitle(`You clicked ${count} times`);

  return (
    <div>
      <p>Você clicou {count} vezes</p>
      <button onClick={incrementCount}>Clique Aqui</button>
    </div>
  )
}

export default Counter;

Quando usar Hooks? Quais problemas ele resolve?

Vamos ver algumas situações em que devemos usar e quais problemas ele resolve a seguir:

1. Você não tem que refatorar um componente funcional em um componente de classe quando ele cresce

Normalmente, há momentos em que um componente React começa com um componente funcional, que depende apenas dos adereços e, posteriormente, evolui para um componente de classe com um estado. Mudar de um componente funcional para um componente de classe requer um pouco de refatoração, dependendo da complexidade do componente.

Com o React Hooks, uma vez que os componentes funcionais têm a capacidade de acessar o estado, o esforço de refatoração será mínimo. Vamos considerar o exemplo abaixo, um componente “burro” que mostra um rótulo com uma contagem.



export function ShowCount(props) {
  return (
    <div> 
      <h1> Count : {props.count} </h1>
    </div>
  );
}

Digamos que precisaremos incrementar a contagem com cliques do mouse e vamos assumir que isso afeta apenas este componente específico. Como primeira etapa, precisamos apresentar o estado ao nosso componente. Vamos dar uma olhada em como faríamos isso com uma abordagem baseada em classe:



export class ShowCount extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
  componentDidMount() {
    this.setState({
      count: this.props.count
    })
  }

  render() {
    return (
      <div>
        <h1> Count : {this.state.count} </h1>
      </div>
    );
  }
 
}

O mesmo componente se parecerá com o seguinte se usarmos hooks.



export function ShowCount(props) {
  const [count, setCount] = useState();

  useEffect(() => {
    setCount(props.count);
  }, [props.count]);

  return (
    <div>
      <h1> Count : {count} </h1>
    </div>
  );
}

2. Você não precisa mais se preocupar com “isso”

“As aulas confundem pessoas e máquinas”

A frase acima é da documentação do React. Uma das razões para essa confusão é a palavra this. Se você está familiarizado com JavaScript, sabe que this não funciona exatamente como em outras linguagens. Quando se trata de React Hooks, você não precisa se preocupar com this. Isso é bom para iniciantes e também para pessoas desenvolvedoras experientes.

3. Não há mais ligações de método

Agora, para o mesmo componente ShowCount acima, vamos apresentar um método para atualizar a contagem do estado quando alguém clica no rótulo.



export class ShowCount extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
    this.handleClickEvent = this.handleClickEvent.bind(this);
  }
  componentDidMount() {
    this.setState({
      count: this.props.count

Introduzimos o método handleClickEvent. Para usá-lo, primeiro temos que vinculá-lo ao this do Componente.



his.handleClickEvent = this.handleClickEvent.bind (this);

Temos que fazer isso porque o contexto de execução é diferente quando o método é executado. Para um desenvolvedor ou desenvolvedora iniciante, isso pode ser um pouco difícil de entender.

Em vez de vincular todos os métodos, existem algumas propostas de sintaxe nas quais você pode contornar isso. Por exemplo, podemos reescrever a função para uma função array.



handleClickEvent = () => {
  this.setState ({contagem: this.state.count + 1});
}

Vamos ver como podemos implementar a mesma funcionalidade com Hooks.



export function ShowCount(props) {
  const [count, setCount] = useState();

  useEffect(() => {
    setCount(props.count);
  }, [props.count]);

  function handleClickEvent() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1 onClick={handleClickEvent}> Count : {count} </h1>
    </div>
  );
}

Como você pode ver, adicionamos apenas a função. Além disso, você pode notar que, quando usamos o manipulador de eventos, removemos o this.

onClick = {handleClickEvent}

4. Mais fácil de desacoplar a lógica da IU, tornando ambas mais reutilizáveis

Usando hooks, a lógica e a IU são mais fáceis de separar. Não há necessidade de HOC ou adereços de renderização. Os hooks fazem isso elegantemente com menos clichês e composições mais intuitivas de interface do usuário e lógica.

Essa “separação elegante” é especialmente crucial ao compartilhar componentes usando ferramentas e plataformas como Bit (Github), pois cada componente (compartilhado de forma independente) é muito mais fácil de entender, manter e reutilizar em diferentes aplicativos.

Separação em paltaformas como BIT do React Hooks

5- Compartilhamento de lógica com estado entre os componentes

Com a abordagem baseada em classe, é difícil compartilhar a lógica entre os componentes. Considere dois componentes em que ambos precisam buscar, classificar e exibir dados de duas fontes diferentes. Embora ambos os componentes tenham a mesma funcionalidade, é difícil compartilhar a lógica porque esses componentes têm fontes e estados diferentes.

Embora possamos usar adereços de renderização e componentes de ordem superior para resolver isso, isso também apresentará um custo adicional, pois temos que reestruturar nossos componentes, o que eventualmente tornará mais difícil de seguir.

O que o React Hooks oferece?

Com o Custom React Hooks, você pode extrair essas lógicas com estado reutilizáveis ​​e testá-las separadamente.

Podemos extrair um gancho personalizado do exemplo ShowCount.



import { useState, useEffect } from "react";

export function useCount(serviceSubject) {
  const [count, setCount] = useState();

  useEffect(() => {
    serviceSubject.subscribe((count) => {
      setCount(count);
    });
    return () => {
      serviceSubject.unsubscribe();
    };
  }, [serviceSubject]);

  return [count, setCount];
}

Usando o hook  personalizado acima, podemos reescrever o componente ShowCount da seguinte maneira. Observe que temos que passar a fonte de dados para o hook personalizado como um parâmetro.



import { useCount } from "./use-count";

export function ShowCount(props) {
  const [count, setCount] = useCount(props.serviceSubject);

  useEffect(() => {
    setCount(-1);
  }, [setCount]);

  return (
    <div>
      <h1> Count : {count} </h1>
    </div>
  );
}

Observe que invocamos getCountsem, um componente pai em vez de um componente ShowCount. Caso contrário, serviceSubject terá um novo valor a cada vez que for executado o ShowCount e não obteremos o resultado que esperamos.

Embora haja muitos motivos para mudar para o React Hooks, mencionamos os motivos mais convincentes. Se você olhar a documentação oficial, verá que existem muitas funcionalidades interessantes no React Hooks.

Limitações do React Hooks

Os React Hooks já existem há algum tempo, mas muitos desenvolvedores do React não os estão usando ativamente. Há duas razões principais por trás disso. 

O primeiro motivo é que muitos desenvolvedores do React já estão envolvidos em um grande projeto, o que requer um esforço significativo para migrar todo o código-base. 

O outro motivo é a familiaridade com as React Classes. Com a experiência, é mais confortável continuar usando as Classes.

Quais as regras do React Hooks?

Cinco regras importantes para Hooks

Antes de criarmos nosso próprio Hook, vamos revisar algumas das principais regras que devemos sempre seguir.

  1. Nunca chame Hooks de dentro de um loop, condição ou função aninhada
  2. Os Hooks devem ficar no nível superior do seu componente
  3. Chame apenas Hooks dos componentes funcionais do React
  4. Nunca chame um Hook de uma função regular
  5. Hooks podem chamar outros Hooks

Se desejar, você pode aplicar essas regras em sua equipe com um plugin ES Lint. Além disso, na mesma página, há boas explicações sobre por que essas regras são necessárias.

Use Hooks apenas no nível superior 

A primeira regra do React Hooks é “apenas chamar hooks no nível superior”. Leia devagar, duas vezes ou mais. Hooks não devem ser colocados dentro de loops, condições ou funções aninhadas. Ao colocar todos os seus hooks no nível superior, o React pode ter certeza de que os hooks de um determinado componente sempre serão chamados na mesma ordem.

À primeira vista, essa regra pode parecer pouco intuitiva. Por que eles precisam ser chamados na mesma ordem em todas as renderizações? Para entender essa regra, você deve entrar no lugar de React.

Explicação

Dê uma olhada em um exemplo simples com duas chamadas de hooks.



const BookForm = () => {
const [title, setTitle] = useState('Game of Thrones');
const [author, setAuthor] = useState( 'George R. R. Martin');
return (
...
);
};

Suponha que renderizamos este componente. O React está monitorando duas partes do estado para nós e precisa de uma maneira de saber o que retornar para cada  chamada useState quando esse componente for renderizado novamente. 

A única coisa sensata para o React fazer aqui é armazenar essas duas partes de estado em uma matriz para que, quando o componente for renderizado novamente, ele possa saber que “a primeira chamada para useState está associada aos dados no índice 0 da matriz e a segunda a chamada para useState está associada aos dados no índice 1 da matriz ”.

['Game of Thrones', 'George R.R. Martin']

Para ser mais explícito, o React vê a primeira chamada useState na renderização inicial, olha o primeiro elemento de sua matriz de hooks para aquele componente, não vê nada e, em seguida, cola o valor inicial que você deu a ele (“Game of Thrones”) no primeiro elemento da matriz. 

Em seguida, ele faz a mesma coisa para a segunda chamada useState, mas com o segundo elemento da matriz, e assim por diante, para quaisquer outras chamadas de hooks que possam estar no componente.

É por isso que é crucial que os hooks sejam chamados na mesma ordem que o componente a ser renderizado. O React mapeia a ordem das chamadas de hooks para elementos do array para saber quais dados estão associados a qual chamada em uma determinada renderização. Aqui está um exemplo em que quebramos essa regra.



const BookForm = () => {
const [title, setTitle] = useState('Game of Thrones');
if (title !==''){
useEffect(()=> console.log(title));
}
const [author, setAuthor] = useState( 'George R. R. Martin');

Observe que agora há quatro hooks sendo usados. Após a renderização inicial, a matriz interna do React fica assim:



[
'Game of Thrones',
() => console.log ('Game of Thrones'),
'George R.R. Martin',
() => console.log ('George R.R Martin'),
]

Suponha agora que o título foi definido como uma string vazia, disparando uma nova renderização do componente. Lembre-se de que o React ainda tem aquele array de 4 elementos em sua memória. 

Como nossa condição if será avaliada como false, o React associará a primeira chamada useState ao primeiro elemento da matriz corretamente, mas, em seguida, associará a segunda chamada useState ao segundo elemento da matriz. Neste caso, é uma função que deve ser associada a uma chamada useEffect do hook. 

Como você pode ver, esse efeito vai se espalhar pelo array e causar todos os tipos de bugs.

Para corrigir esse problema específico, basta mover a condição para o corpo da função passada para a chamada useEffect.

Os 6 Hooks mais utilizados!

useState

É o hook mais importante e frequentemente usado. O objetivo deste hook é lidar com dados reativos. Quaisquer dados que mudam no aplicativo são chamados de estado, e, quando qualquer um dos dados muda, o React renderiza novamente a IU.



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

useEffect

Ele nos permite implementar todos os hooks do ciclo de vida a partir de uma única função de API .



// isso será executado quando o componente for montado e sempre que os dados com estado mudarem
React.useEffect(() => {
    alert('Hey, Nads here!');
});

// isso será executado quando o componente for inicializado pela primeira vez
React.useEffect(() => {
    alert('Hey, Nads here!');
}, []);

// this will run only when count state changes
React.useEffect(() => {
    fetch('nads').then(() => setLoaded(true));
}, [count]);

// isso será executado quando o componente for destruído ou antes que o componente seja removido da IU.
React.useEffect(() => {
    alert('Hey, Nads here');

    return () => alert('Goodbye Component');
});

useContext

Este hook nos permite trabalhar com Reacts Context API, que é um mecanismo que nos permite compartilhar dados dentro de sua árvore de componentes sem passar por adereços. 



const ans = {
    right: '✅',
    wrong: '❌'
}

const AnsContext = createContext(ans);

function Exam(props) {
    return (

useCallback



function useCallbackDemo() {
    const [count, setCount] = useState(60);

    const showCount = React.useCallback(() => {
        alert(`Count ${count}`);
    }, [count])

    return <> <SomeChild handler = {showCount} /> </>
}

useMemo

Este hooks ajudará a otimizar o custo computacional ou melhorar o desempenho. É usado principalmente quando precisamos fazer cálculos.

function useMemo() {

    const [count, setCount] = React.useState(60);

    const expensiveCount = useMemo(() => {
        return count**2;
    }, [count]) // recompute quando a contagem mudar.
}

useRef

Este hooks nos permite criar um objeto mutável. É usado quando o valor mantém as alterações, como no caso do hook useState, mas a diferença é que ele não dispara uma nova renderização quando o valor muda.

O caso de uso comum disso é capturar elementos HTML do DOM.



function App() {
    const myBtn = React.useRef(null);
    const handleBtn = () => myBtn.current.click();
    return (
        <button ref={myBtn} onChange={handleBtn} >
        </button>
    )
}

Custom Hooks: construindo seus próprios hooks!

Os Custom React Hooks são uma ferramenta essencial que permite adicionar uma funcionalidade especial e exclusiva aos seus aplicativos React.

Em muitos casos, se você deseja adicionar um determinado recurso ao seu aplicativo, basta instalar uma biblioteca de terceiros feita para resolver o seu problema. Mas se tal biblioteca ou gancho não existir, o que você faz?

Como desenvolvedor ou desenvolvedora de React, é importante aprender o processo de criação de hooks personalizados para resolver problemas ou adicionar recursos ausentes em seus próprios projetos React.

Um hook personalizado permite que você extraia a lógica de alguns componentes para uma função reutilizável.

Um hook personalizado é uma função Javascript que começa com o uso e essa chamada pode outros hooks. Lembre-se de que componentes e hooks são funções, portanto, não estamos criando nenhum conceito novo aqui. Estamos apenas refatorando nosso código em outra função para torná-lo reutilizável.

Como os hooks são apenas funções Javascript, eles não precisam de um componente React para realmente existir.



import { useState, useEffect } from "react";

const useWindowsWidth = () => {
  const [isScreenSmall, setIsScreenSmall] = useState(false);

  let checkScreenSize = () => {
    setIsScreenSmall(window.innerWidth < 600);
  };
  useEffect(() => {
    checkScreenSize();
    window.addEventListener("resize", checkScreenSize);

    return () => window.removeEventListener("resize", checkScreenSize);
  }, []);

  return isScreenSmall;
};

export default useWindowsWidth;

Extraímos essa funcionalidade dentro da função useWindowWidth. Agora, podemos importá-la para qualquer lugar que quisermos usá-la!



import React from 'react'
import useWindowWidth from './useWindowWidth.js'

const MyComponent = () => {
  const onSmallScreen = useWindowWidth();

  return (
    //Retorna alguns elementos
  )
}

Importante lembrar que qualquer coisa que você usar em um gancho dentro de um componente pode ser extraído e usado em seus hooks personalizados.

Por exemplo, vamos imaginar que você tenha componentes que exibem uma lista de comentários com base em um artigo. Podemos imaginar algo entre essas linhas:

const ArticleWithComments = (articleId) => {
  const [comments, setComments] = useState([])
  const [error, setError] = useState(null)

  let handleCommentsSuccessFetch = (articleComments) => setComments(articleComments)

  let handleError = error => setError(error)

  useEffect(() => {
    fetchComments(articleId, handleCommentsSuccessFetch, handleError)
  }, [])

  return (
    //Faça algo no DOM
  )
}

const BlogPostWithComments = (blogPostId) => {
  const [comments, setComments] = useState([])
  const [error, setError] = useState(null)

  let handleCommentsSuccessFetch = (blogPostComments) => setComments(blogPostComments)

  let handleError = error => setError(error)

  useEffect(() => {
    fetchComments(blogPostId, handleCommentsSuccessFetch, handleError)
  }, [])

  return (
    // Faça algo no DOM
  )
}

Neste exemplo, temos dois componentes. Ambos buscam uma lista de comentários com base em uma ID, seja de um artigo ou de uma postagem de blog. 

No gancho useEffect, temos uma chamada de API que recupera esses comentários com duas funções. Um em caso de sucesso define os comentários no estado, o segundo em caso de erro define-o no estado.

Porém, a funcionalidade é duplicada entre esses dois componentes. Felizmente, podemos extrair essa funcionalidade dentro de um gancho personalizado:

const useCommentsRetriever = (entityId) => {
  const [comments, setComments] = useState([]);
  const [error, setError] = useState(null);

  let handleCommentsSuccessFetch = (comments) => setComments(comments);

  let handleError = (error) => setError(error);

  useEffect(() => {
    fetchComments(entityId, handleCommentsSuccessFetch, handleError);
  }, []);

  return [comments, error];
};

Isolamento de hooks personalizados

Se você usar os mesmos hooks personalizados em dois componentes, eles não compartilharão o estado. O estado em nosso BlogPostWithComments será completamente separado do estado em nosso ArticleWithComments. Cada gancho personalizado cria uma nova função que usa useState e useEffect do React. Podemos usar vários hooks dentro do mesmo componente.

Hooks personalizados permitem que você realmente use sua imaginação ao escrever seu código React. Você pode extrair e compartilhar a lógica de uma maneira que não era possível com os componentes da classe.

Divirta-se!

Instalando o React Hooks

Abra seu terminal, pois vamos usar um gerador de código famoso para aplicativos React, chamado create-react-app :

npm install create-react-app -gcreate-react-app react-hooks

Agora, podemos ver uma pasta chamada ./react-hooks, então vamos lá e consideramos que é a raiz de nosso aplicativo.

Também precisamos instalar um pacote de pares chamado react-dom exatamente da mesma versão.



npm install [email protected] --savenpm install [email protected] axios --save

Não se esqueça de iniciar o aplicativo:



npm start

Neste artigo, aprendemos mais sobre a usabilidade dos React Hooks e como eles podem ajudar a poupar algumas linhas de código. Esperamos que este artigo ajude você a entender melhor os fundamentos dos Hooks,permita que você desenvolva esses exemplos e crie coisas novas e incríveis. Se foi útil para você, compartilhe e divulgue!

Gostou do nosso texto? Que tal ler agora sobre a função JavaScript replace?

Deixe um comentário
Você também pode gostar