Começando com a API React Hooks
Publicados: 2022-03-10Quando o React 16.8 foi lançado oficialmente no início de fevereiro de 2019, ele foi enviado com uma API adicional que permite usar o estado e outros recursos no React sem escrever uma classe. Essa API adicional é chamada de Hooks e está se tornando popular no ecossistema React, desde projetos de código aberto até o uso em aplicativos de produção.
React Hooks são totalmente opt-in, o que significa que reescrever o código existente é desnecessário, eles não contêm nenhuma alteração importante e estão disponíveis para uso com o lançamento do React 16.8. Alguns desenvolvedores curiosos têm feito uso da API Hooks antes mesmo de ser lançada oficialmente, mas naquela época ela não era estável e era apenas um recurso experimental. Agora é estável e recomendado para os desenvolvedores do React usarem.
Nota : Não falaremos sobre React ou JavaScript em geral. Um bom conhecimento de ReactJS e JavaScript será útil enquanto você trabalha neste tutorial.
O que são Hooks React?
React Hooks são funções embutidas que permitem que desenvolvedores React usem métodos de estado e ciclo de vida dentro de componentes funcionais, eles também trabalham em conjunto com o código existente, para que possam ser facilmente adotados em uma base de código. A maneira como os Hooks foram apresentados ao público foi que eles permitem que os desenvolvedores usem o estado em componentes funcionais, mas sob o capô, os Hooks são muito mais poderosos do que isso. Eles permitem que os desenvolvedores do React aproveitem os seguintes benefícios:
- Reutilização de código aprimorada;
- Melhor composição de código;
- Melhores padrões;
- Compartilhamento de lógica não visual com o uso de ganchos personalizados;
- Flexibilidade na movimentação para cima e para baixo na árvore de
components
.
Com o React Hooks, os desenvolvedores têm o poder de usar componentes funcionais para quase tudo o que precisam fazer, desde renderizar a interface do usuário até manipular o estado e também a lógica - o que é muito legal.
Motivação por trás do lançamento do React Hooks
De acordo com a documentação oficial do ReactJS, a seguir está a motivação por trás do lançamento do React Hooks:
- Reutilizar a lógica com estado entre componentes é difícil.
Com Hooks, você pode reutilizar a lógica entre seus componentes sem alterar sua arquitetura ou estrutura. - Componentes complexos podem ser difíceis de entender.
Quando os componentes se tornam maiores e realizam muitas operações, torna-se difícil de entender a longo prazo. Os ganchos resolvem isso permitindo que você separe um componente único específico em várias funções menores com base em quais partes desse componente separado estão relacionadas (como configurar uma assinatura ou buscar dados), em vez de ter que forçar uma divisão com base nos métodos do ciclo de vida. - As aulas são bastante confusas.
As aulas são um obstáculo para aprender React corretamente; você precisaria entender comothis
funciona em JavaScript, que difere de outras linguagens. O React Hooks resolve esse problema permitindo que os desenvolvedores usem os melhores recursos do React sem precisar usar classes.
As regras dos ganchos
Existem duas regras principais que devem ser rigorosamente seguidas, conforme declarado pela equipe principal do React, descritas na documentação da proposta de ganchos.
- Certifique-se de não usar Hooks dentro de loops, condições ou funções aninhadas;
- Use apenas Hooks de dentro de React Functions.
Ganchos de reação básicos
Existem 10 hooks embutidos que foram enviados com o React 16.8, mas os hooks básicos (comumente usados) incluem:
-
useState()
-
useEffect()
-
useContext()
-
useReducer()
Estes são os 4 ganchos básicos que são comumente usados por desenvolvedores React que adotaram React Hooks em suas bases de código.
useState()
O gancho useState()
permite que os desenvolvedores do React atualizem, manipulem e manipulem o estado dentro de componentes funcionais sem precisar convertê-lo em um componente de classe. Vamos usar o trecho de código abaixo é um componente simples de contador de idade e o usaremos para explicar o poder e a sintaxe do gancho useState()
.
function App() { const [age, setAge] = useState(19); const handleClick = () => setAge(age + 1) return <div> I am {age} Years Old <div> <button onClick={handleClick}>Increase my age! </button> </div> </div> }
Se você notou, nosso componente parece bem simples, conciso e agora é um componente funcional e também não tem o nível de complexidade que um componente de classe teria.
O useState()
recebe um estado inicial como argumento e então retorna, fazendo uso da desestruturação de array em JavaScript, as duas variáveis no array podem ser nomeadas what. A primeira variável é o estado real, enquanto a segunda variável é uma função destinada a atualizar o estado fornecendo um novo estado.
É assim que nosso componente deve ficar quando renderizado em nosso aplicativo React. Ao clicar no botão “Aumentar minha idade”, o estado da idade mudará e o componente funcionará como um componente de classe com estado.
useEffect()
O gancho useEffect()
aceita uma função que contém código eficaz. Em componentes funcionais, efeitos como mutações, assinaturas, temporizadores, registro e outros efeitos não podem ser colocados dentro de um componente funcional porque isso levaria a muitas inconsistências quando a interface do usuário é renderizada e também a erros confusos.
Ao usar o gancho useEffect()
, a função effectual passada para ele será executada logo após a exibição da renderização na tela. Os efeitos são basicamente espreitados na forma imperativa de construir UIs que é bem diferente da forma funcional do React.
Por padrão, os efeitos são executados principalmente após a conclusão da renderização, mas você tem a opção de ativá-los também quando certos valores são alterados.
O gancho useEffect()
é usado principalmente para efeitos colaterais que geralmente são usados para interações com a API Browser/DOM ou busca de dados ou assinaturas semelhantes a APIs externas. Além disso, se você já estiver familiarizado com o funcionamento dos métodos de ciclo de vida React, você também pode pensar no gancho useEffect()
como montagem , atualização e desmontagem de componentes — tudo combinado em uma função. Ele nos permite replicar os métodos do ciclo de vida em componentes funcionais.
Usaremos os trechos de código abaixo para explicar a maneira mais básica possível usando o gancho useEffect()
.
Etapa 1: defina o estado do seu aplicativo
import React, {useState} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App
Assim como discutimos na seção anterior sobre como usar o gancho useState()
para manipular o estado dentro dos componentes funcionais, nós o usamos em nosso trecho de código para definir o estado do nosso aplicativo que renderiza meu nome completo.
Etapa 2: chame o gancho useEffect
import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({FirstName: 'Shedrack', surname: 'Akintayo'}) }, [])//pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App
Agora importamos o gancho useEffect
e também usamos a função useEffect()
para definir o estado de nossa propriedade name e surname, que é bastante organizada e concisa.
Você deve ter notado o gancho useEffect
no segundo argumento que é um array vazio; isso ocorre porque contém uma chamada para o setFullName
que não possui uma lista de dependências. Passar o segundo argumento evitará uma cadeia infinita de atualizações ( componentDidUpdate()
) e também permitirá que nosso useEffect()
atue como um método de ciclo de vida componentDidMount
e renderize uma vez sem renderizar novamente a cada alteração na árvore.
Nosso aplicativo React agora deve ficar assim:
Também podemos usar alterar a propriedade title
do nosso aplicativo dentro da função useEffect()
chamando a função setTitle()
, assim:
import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({firstName: 'Shedrack', surname: 'Akintayo'}) setTitle({'My Full Name'}) //Set Title }, [])// pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App
Agora, depois que nosso aplicativo foi renderizado novamente, ele agora mostra o novo título.
useContext()
O gancho useContext()
aceita um objeto de contexto, ou seja, o valor que é retornado de React.createContext
e, em seguida, retorna o valor de contexto atual para esse contexto.
Este gancho fornece aos componentes funcionais acesso fácil ao contexto do seu aplicativo React. Antes que o gancho useContext
fosse introduzido, você precisaria configurar um contextType
ou um <Consumer>
para acessar seu estado global passado de algum provedor em um componente de classe.
Basicamente, o gancho useContext
funciona com a API React Context, que é uma maneira de compartilhar dados profundamente em todo o seu aplicativo sem a necessidade de passar manualmente os adereços do seu aplicativo por vários níveis. Agora, o useContext()
torna o uso de Context um pouco mais fácil.
Os trechos de código abaixo mostrarão como a Context API funciona e como o useContext
Hook a torna melhor.
A maneira normal de usar a API de contexto
import React from "react"; import ReactDOM from "react-dom"; const NumberContext = React.createContext(); function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); } function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));
Vamos agora dividir o trecho de código e explicar cada conceito.
Abaixo, estamos criando um contexto chamado NumberContext
. Destina-se a retornar um objeto com dois valores: { Provider, Consumer }
.
const NumberContext = React.createContext();
Em seguida, usamos o valor Provider
que foi retornado do NumberContext
que criamos para disponibilizar um valor específico para todos os filhos.
function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); }
Com isso, podemos usar o valor Consumer
que foi retornado do NumberContext
que criamos para obter o valor que disponibilizamos para todos os filhos. Se você notou, este componente não recebeu nenhum adereço.
function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));
Observe como conseguimos obter o valor do componente App
no componente Display
envolvendo nosso conteúdo em um NumberContext.Consumer
e usando o método render props para recuperar o valor e renderizá-lo.
Tudo funciona bem e o método render props que usamos é um padrão muito bom para lidar com dados dinâmicos, mas a longo prazo, ele introduz alguns aninhamentos desnecessários e confusão se você não estiver acostumado.
Usando o método useContext
Para explicar o método useContext
vamos reescrever o componente Display
usando o gancho useContext.
// import useContext (or we could write React.useContext) import React, { useContext } from 'react'; // old code goes here function Display() { const value = useContext(NumberContext); return <div>The answer is {value}.</div>; }
Isso é tudo que precisamos fazer para mostrar nosso valor. Bem legal, certo? Você chama o gancho useContext()
e passa o objeto de contexto que criamos e pegamos o valor dele.
Nota: Não esqueça que o argumento que é passado para o gancho useContext deve ser o próprio objeto de contexto e qualquer componente que chame o useContext sempre será renderizado novamente quando o valor do contexto for alterado.
useReducer()
O gancho useReducer
é usado para lidar com estados complexos e transições de estado. Ele recebe uma função reducer
e também uma entrada de estado inicial; em seguida, ele retorna o estado atual e também uma função de dispatch
como saída por meio da desestruturação de array.
O código abaixo é a sintaxe adequada para usar o gancho useReducer
.
const [state, dispatch] = useReducer(reducer, initialArg, init);
É uma espécie de alternativa ao gancho useState
; geralmente é preferível useState
quando você tem lógica de estado complexa que tem a ver com vários subvalores ou quando o próximo estado depende do anterior.
Outros ganchos de reação disponíveis
useCallback | Esse gancho retorna uma função de retorno de chamada que é memorizada e que só muda se uma dependência na árvore de dependências for alterada. |
useMemo | Este hook retorna um valor memoizado, você pode passar uma função “create” e também um array de dependências. O valor que ele retorna só usará o valor memorizado novamente se uma das dependências na árvore de dependências for alterada. |
useRef | Este gancho retorna um objeto ref mutável cuja propriedade .current é inicializada para o argumento passado ( initialValue ). O objeto retornado estará disponível por toda a vida útil do componente. |
useImperativeHandle | Este gancho é usado para personalizar o valor da instância que é disponibilizado para componentes pai ao usar refs no React. |
useLayoutEffect | Esse gancho é semelhante ao gancho useEffect , no entanto, ele é acionado de forma síncrona após todas as mutações do DOM. Ele também renderiza da mesma maneira que componentDidUpdate e componentDidMount . |
useDebugValue | Este gancho pode ser usado para exibir um rótulo para ganchos personalizados no React Dev Tools. É muito útil para depurar com o React Dev Tools. |
Ganchos de reação personalizados
Um “gancho customizado” é uma função JavaScript cujos nomes são prefixados com a palavra use
e podem ser usados para chamar outros Ganchos. Também permite extrair a lógica do componente em funções reutilizáveis; são funções JavaScript normais que podem fazer uso de outros Hooks dentro dele e também contêm uma lógica stateful comum que pode ser usada em vários componentes.
Os trechos de código abaixo demonstram um exemplo de um React Hook customizado para implementação de rolagem infinita (por Paulo Levy):
import { useState } from "react"; export const useInfiniteScroll = (start = 30, pace = 10) => { const [limit, setLimit] = useState(start); window.onscroll = () => { if ( window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight ) { setLimit(limit + pace); } }; return limit; };
Este Hook customizado aceita dois argumentos que são start
e pace
. O argumento start é o número inicial de elementos a serem renderizados, enquanto o argumento pace é o número subsequente de elementos a serem renderizados. Por padrão, os argumentos start
e pace
são definidos para 30
e 10
, respectivamente, o que significa que você pode realmente chamar o Hook sem nenhum argumento e esses valores padrão serão usados.
Então, para usar esse Hook dentro de um aplicativo React, nós o usaríamos com uma API online que retorna dados 'falsos':
import React, { useState, useEffect } from "react"; import { useInfiniteScroll } from "./useInfiniteScroll"; const App = () => { let infiniteScroll = useInfiniteScroll(); const [tableContent, setTableContent] = useState([]); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/") .then(response => response.json()) .then(json => setTableContent(json)); }, []); return ( <div style={{ textAlign: "center" }}> <table> <thead> <tr> <th>User ID</th> <th>Title</th> </tr> </thead> <tbody> {tableContent.slice(0, infiniteScroll).map(content => { return ( <tr key={content.id}> <td style={{ paddingTop: "10px" }}>{content.userId}</td> <td style={{ paddingTop: "10px" }}>{content.title}</td> </tr> ); })} </tbody> </table> </div> ); }; export default App;
O código acima renderizará uma lista de dados falsos ( userID
e title
) que fazem uso do gancho de rolagem infinita para exibir o número inicial de dados na tela.
Conclusão
Espero que você tenha gostado de trabalhar com este tutorial. Você sempre pode ler mais sobre React Hooks nas referências abaixo.
Se você tiver alguma dúvida, pode deixá-las na seção de comentários e ficarei feliz em responder a cada uma!
O repositório de suporte para este artigo está disponível no Github.
Recursos e leitura adicional
- “Referência da API Hooks,” React.js Docs
- “O que são React Hooks?”, Robin Wieruch
- “Como funciona o gancho
useContext
”, Dave Ceddia - “React Hooks: How To Use
useEffect()
”, Hossein Ahmadi, Medium - “Escrevendo seus próprios ganchos de reação personalizados”, Aayush Jaiswal, Medium
- “Receitas fáceis de entender do React Hook,” Gabe Ragland, useHooks()