-
Notifications
You must be signed in to change notification settings - Fork 56
Docs: adiciona artigo sobre Custom Hooks #144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| <p align="center"> | ||
| <a href="https://github.com/he4rt/4noobs" target="_blank" title="Clique para visualizar mais informações sobre o projeto 4noobs"> | ||
| <img src="../../assets/global/header-4noobs.svg" alt="Cabeçalho do repositório representado pelo logotipo da He4rt, simbolizado por um coração roxo, na esquerda e a tipografia '4 noobs by He4rt devs' na direita"> | ||
| </a> | ||
| </p> | ||
|
|
||
| # **CUSTOM HOOKS: Compartilhando lógica entre componentes** | ||
|
|
||
| ## O que é um Custom Hook? | ||
|
|
||
| Hook personalizado é uma função JavaScript na qual é possível reutilizar | ||
| sua lógica em diversos componentes da aplicação. Imagine que na sua | ||
| aplicação você tem vários componentes que precisam fazer requisições a | ||
| uma API, ou salvar algo no local storage. Se você tiver um hook | ||
| personalizado que faça tais coisas, não será necessário repetir o mesmo | ||
| código várias vezes, apenas chamar o hook. | ||
|
|
||
| Um hook personalizado não é um recurso separado do React, é apenas uma | ||
| função comum que usa, por baixo dos panos, hooks nativas como **`useState`** | ||
| e **`useEffect`**. | ||
|
|
||
| Hooks personalizados não compartilham estados entre os componentes: cada | ||
| componente que utiliza o hook possui seu estado isolado, a função | ||
| compartilha apenas a lógica. A função precisa, obrigatoriamente, começar | ||
| com a palavra **`use`**, essa convenção avisa o React que aquela função pode | ||
| chamar outras hooks internamente, permitindo que ferramentas como o | ||
| ESLint verifiquem se as regras das hooks estão sendo seguidas corretamente. | ||
|
|
||
| ## Vantagens dos Custom Hooks: | ||
|
|
||
| - **Reutilização de lógica:** Evita duplicar o mesmo código (fetch de API, manipulação de formulário, localStorage, etc.) em vários componentes diferentes. | ||
|
|
||
| - **Componentes mais limpos:** A lógica complexa fica isolada na hook, deixando o componente focado apenas na renderização. | ||
|
|
||
| - **Facilidade de manutenção:** Se precisar corrigir um bug ou mudar uma regra de negócio, você altera em um único lugar (a hook), em vez de em cada componente que repete a lógica. | ||
|
|
||
| - **Testabilidade:** Como a lógica fica separada da interface, fica mais fácil testar a hook isoladamente, sem precisar renderizar todo o componente. | ||
|
|
||
| - **Não quebra a árvore de componentes:** Diferente de HOCs e render props, custom hooks não adicionam camadas extras de componentes na árvore, evitando o "wrapper hell". | ||
|
|
||
| - **Compartilhamento sem acoplamento:** Vários componentes podem usar a mesma lógica sem precisar estar relacionados entre si (não é necessário passar props entre pai e filho). | ||
|
|
||
| ## Exemplo Prático: useFetch | ||
|
|
||
| Este hook encapsula toda a lógica de requisição a uma API, controlando | ||
| os estados de carregamento, erro e dados retornados. | ||
|
|
||
| ### O código: | ||
|
|
||
| ```javascript | ||
| import { useState, useEffect } from 'react'; | ||
|
|
||
| export function useFetch(url){ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (suggestion): Adicionar cleanup no useEffect pra evitar race condition Como o useEffect dispara a cada mudança de url, requisições podem resolver fora de ordem, uma resposta antiga chega depois da nova e sobrescreve o data correto. Como é um tutorial, vale mostrar o padrão de cleanup, que é o jeito idiomático de lidar com isso: O Alternativa mais robusta seria AbortController pra cancelar o fetch de verdade, mas o ignore já resolve o problema visível e é mais simples de explicar para um iniciante. |
||
| const [data, setData] = useState(null); | ||
| const [loading, setLoading] = useState(false); | ||
| const [error, setError] = useState(null); | ||
|
|
||
| useEffect( () => { | ||
| if (!url) { | ||
| setLoading(false); | ||
| return; | ||
| } | ||
|
|
||
| let ignore = false; // flag: ignora resultado se o effect já foi limpo | ||
|
|
||
| //Função que busca a API | ||
| const fetchData = async () => { | ||
| setLoading(true); //Ativa o Loading quando começa a busca | ||
| setError(null); // Reseta erros anteriores | ||
|
|
||
| try{ | ||
| const response = await fetch(url); | ||
| const json = await response.json(); | ||
|
|
||
| if (!ignore) setData(json); | ||
| }catch (err){ | ||
| if (!ignore) { | ||
| setError(err.message); | ||
| setData(null); | ||
| } | ||
| }finally{ | ||
| if (!ignore) setLoading(false); | ||
| } | ||
| }; | ||
|
|
||
| fetchData(); | ||
|
|
||
| // Cleanup: roda quando a url muda ou o componente desmonta. | ||
| return () => { | ||
| ignore = true; | ||
| }; | ||
| }, [url]); //UseEffect roda toda vez que a variável url muda. | ||
|
|
||
| //Retorna os estados em forma de objetos, dessa maneira é possível pegar o qual variável quiser. | ||
| return { data, loading, error }; | ||
| } | ||
| ``` | ||
|
|
||
| ### Como funciona? | ||
|
|
||
| - Recebe uma **`url`** como parâmetro. | ||
| - Retorna um objeto com três valores: **`data`** (os dados retornados), | ||
| **`loading`** (se a requisição está em andamento) e **`error`** (mensagem de | ||
| erro, se houver). | ||
| - O **`useEffect`** roda automaticamente sempre que a **`url`** mudar, disparando | ||
| uma nova requisição. | ||
|
|
||
| ### Usando a hook em um componente: | ||
|
|
||
| ```jsx | ||
| import {useFetch} from 'caminho_da_funcao' | ||
|
|
||
| function ListaPokemon() { | ||
| const { data, loading, error } = useFetch('https://pokeapi.co/api/v2/pokemon'); | ||
|
|
||
| if (loading) return <p>Carregando...</p>; | ||
| if (error) return <p>Erro: {error}</p>; | ||
|
|
||
| return ( | ||
| <ul> | ||
| {data.results.map((pokemon) => ( | ||
| <li key={pokemon.name}>{pokemon.name}</li> | ||
| ))} | ||
| </ul> | ||
| ); | ||
| } | ||
| ``` | ||
| Perceba como o componente ficou mais limpo: Ele não sabe **como** a requisição é feita, apenas **usa** o resultado. | ||
|
|
||
| [Ir para a próxima seção](./9-React%20Error%20Boundaries.md) | ||
|
|
||
| <p align="center">Made with 💜</p> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (block): Antes disso, precisamos colocar o link para a próxima seção, tipo como é feito aqui: https://github.com/he4rt/react4noobs/blob/master/docs/Iniciando%20com%20React/8.3-useContext.md |
||
|
|
||
| <p align="center"> | ||
| <a href="https://github.com/he4rt/4noobs" target="_blank"> | ||
| <img src="../../assets/global/footer-4noobs.svg" width="380" alt="Tipografia com o título '4 noobs by He4rt devs' e o slogan 'Da comunidade para a comunidade 💜'"> | ||
| </a> | ||
| </p> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(block): Ajuste no local do arquivo
Precisamos mover esse arquivo pra essa pasta: https://github.com/he4rt/react4noobs/tree/master/docs/Iniciando%20com%20React
E renomear ele pra
8.8-custom-hooks