Quais são os hooks no React?
sobes.tech IA
Resposta da IA
No React, a partir da versão 16.8, os hooks permitem que os componentes funcionais gerenciem o estado e usem ciclos de vida, que anteriormente estavam disponíveis apenas para componentes de classe.
Aqui estão os principais hooks integrados:
-
useState: Permite adicionar estado interno a um componente funcional. Retorna um par: o estado atual e uma função para atualizá-lo.// Exemplo useState import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); // Inicialização do estado com 0 return ( <div> <p>Você clicou {count} vezes</p> <button onClick={() => setCount(count + 1)}> Clique em mim </button> </div> ); } -
useEffect: Permite realizar efeitos colaterais em componentes funcionais. Semelhante aos métodos do ciclo de vida de componentes de classe (componentDidMount,componentDidUpdate,componentWillUnmount).// Exemplo useEffect import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Executa após cada renderização useEffect(() => { document.title = `Você clicou ${count} vezes`; }); // Executa apenas na primeira renderização (matriz de dependências vazia) useEffect(() => { console.log('Componente montado'); return () => { console.log('Componente desmontado'); // Função de limpeza }; }, []); // Executa ao alterar count useEffect(() => { console.log('Count mudou:', count); }, [count]); return ( <div> <p>Você clicou {count} vezes</p> <button onClick={() => setCount(count + 1)}> Clique em mim </button> </div> ); } -
useContext: Permite subscrever-se às mudanças do contexto do React. Aceita um objeto de contexto criado comReact.createContext().// Exemplo useContext import React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); // Criação do contexto function ThemedButton() { const theme = useContext(ThemeContext); // Uso do contexto return ( <button className={theme}> Botão no tema {theme} </button> ); } function App() { return ( <ThemedButton /> ); } -
useReducer: Alternativa aouseStatepara gerenciar estados mais complexos, que incluem múltiplos subvalores ou quando o próximo estado depende do anterior. Semelhante aos reducers no Redux.// Exemplo useReducer import React, { useReducer } from 'react'; const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({ type: 'increment' })}>+</button> <button onClick={() => dispatch({ type: 'decrement' })}>-</button> </> ); } -
useCallback: Memoiza uma função de callback. Retorna uma versão memorizada do callback que só muda se alguma das dependências mudar. Útil para evitar renderizações desnecessárias de componentes filhos ao passar callbacks.// Exemplo useCallback import React, { useState, useCallback } from 'react'; function Parent({ addTodo }) { const [count, setCount] = useState(0); const handleAddTodo = useCallback(() => { addTodo(); }, [addTodo]); // Dependência de addTodo return ( <> <button onClick={() => setCount(count + 1)}> Incrementar contador </button> <Child onAddItem={handleAddTodo} /> </> ); } function Child({ onAddItem }) { console.log('Child renderiza'); // Será renderizado apenas quando onAddItem mudar return <button onClick={onAddItem}>Adicionar item</button>; } -
useMemo: Memoiza um valor calculado. Retorna um valor memorizado que só é recalculado se alguma dependência mudar. Útil para melhorar o desempenho em cálculos caros.// Exemplo useMemo import React, { useMemo, useState } from 'react'; function expensiveCalculation(num) { console.log('Executando cálculo caro...'); for (let i = 0; i < 1000000; i++) { num += 1; } return num; } function Example() { const [count, setCount] = useState(0); const [todos, setTodos] = useState([]); const calculation = useMemo(() => expensiveCalculation(count), [count]); // Dependência de count const addTodo = () => { setTodos(t => [...t, "Novo Todo"]); }; return ( <div> <div> <h2>Meus Todo</h2> {todos.map((todo, index) => ( <p key={index}>{todo}</p> ))} <button onClick={addTodo}>Adicionar Todo</button> </div> <hr /> <div> Contador: {count} <button onClick={() => setCount(c => c + 1)}>+</button> <h2>Cálculo caro</h2> {calculation} </div> </div> ); } -
useRef: Permite criar uma referência mutável que persiste durante toda a vida do componente. Geralmente usado para acessar elementos DOM ou armazenar qualquer valor mutável que não cause renderização ao mudar.// Exemplo useRef import React, { useRef } from 'react'; function TextInputWithFocusButton() { const inputEl = useRef(null); // Criando referência const onButtonClick = () => { // current aponta para o elemento DOM montado inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> // Associando referência <button onClick={onButtonClick}>Focar no campo de entrada</button> </> ); } -
useImperativeHandle: Configura o descriptor do objeto que é exposto ao componente pai ao usarref. Permite que o componente filho exponha certos métodos ao componente pai. Usado junto comforwardRef.// Exemplo useImperativeHandle import React, { useRef, useImperativeHandle, forwardRef } from 'react'; const MyInput = forwardRef((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focusInput: () => { inputRef.current.focus(); } })); return <input ref={inputRef} {...props} />; }); function ParentComponent() { const inputRef = useRef(); const handleFocus = () => { inputRef.current.focusInput(); // Chamada ao método do componente filho }; return ( <div> <MyInput ref={inputRef} /> <button onClick={handleFocus}>Focar via Parent</button> </div> ); } -
useLayoutEffect: Igual aouseEffect, mas é executado de forma síncrona após todas as mutações do DOM. Útil para ler dados do DOM ou fazer mutações que precisam ocorrer antes do navegador pintar a tela. Pode bloquear a renderização.// Exemplo useLayoutEffect import React, { useLayoutEffect, useRef } from 'react'; function Tooltip({ children, text }) { const ref = useRef(null); useLayoutEffect(() => { if (ref.current) { // Cálculos baseados no DOM antes do repaint const { top, height } = ref.current.getBoundingClientRect(); console.log(`O elemento está em ${top} com altura ${height}`); } }, [children]); return ( <span ref={ref} title={text}> {children} </span> ); } -
useDebugValue: Exibe uma etiqueta personalizada para hooks no React DevTools. Usado em hooks personalizados para depuração.// Exemplo useDebugValue import React, { useState, useDebugValue } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); // Exibe 'Friend Status: Offline' ou 'Friend Status: Online' no DevTools useDebugValue(isOnline === true ? 'Online' : 'Offline'); // ... lógica para obter o status do amigo return isOnline; } function FriendListItem({ friend }) { const isOnline = useFriendStatus(friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {friend.name} - {isOnline ? 'Online' : 'Offline'} </li> ); }
Além dos hooks integrados, existem hooks personalizados (Custom Hooks). São funções JavaScript que começam com "use". Permitem reutilizar lógica de estado entre componentes. Um hook personalizado pode chamar outros hooks.
// Exemplo de hook personalizado
import { useState, useEffect } from 'react';
function useWindowSize() {
const [size, setSize] = useState([window.innerWidth, window.innerHeight]);
useEffect(() => {
const handleResize = () => {
setSize([window.innerWidth, window.innerHeight]);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return size;
}
function MyComponent() {
const [width, height] = useWindowSize(); // Uso do hook personalizado
return (
<p>Tamanho da janela: {width}x{height}</p>
);
}
É importante seguir as Regras dos Hooks:
- Chamar hooks apenas no nível superior de componentes React ou hooks personalizados. Não chamá-los dentro de loops, condições ou funções aninhadas.
- Chamar hooks apenas de componentes funcionais React ou hooks personalizados. Não chamá-los de funções JavaScript normais ou métodos de componentes de classe.