Manipulação de Eventos
Responda a interações do usuário com manipuladores de eventos type-safe.
Busque em todas as páginas da documentação
Responda a interações do usuário com manipuladores de eventos type-safe.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
// Manipulador inline
<button onClick={() => console.log("clicado")}>Clique em mim</button>
// Manipulador nomeado
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
console.log(e.currentTarget.name);
}
<button name="salvar" onClick={handleClick}>Salvar</button>
// Passando dados para manipuladores
<button onClick={() => deleteItem(item.id)}>Excluir</button>
// Impedindo o padrão
<form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>Quando usar isso: Sempre que precisar responder a cliques, pressionamentos de tecla, envios de formulário, alterações de foco ou qualquer outro evento DOM.
"use client";
import { useState, useCallback } from "react";
interface LogEntry {
id: number;
type: string;
detail: string;
timestamp: string;
}
let entryId = 0;
export function EventPlayground() {
const [log, setLog] = useState<LogEntry[]>([]);
const addLog = useCallback((type: string, detail: string) => {
setLog(prev => [
{ id: ++entryId, type, detail, timestamp: new Date().toLocaleTimeString() },
...prev.slice(0, 9), // mantém os últimos 10
]);
}, []);
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
addLog("click", `Botão "${e.currentTarget.textContent}" em (${e.clientX}, ${e.clientY})`);
}
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === "Enter") {
addLog("keydown", `Enter pressionado - valor: "${e.currentTarget.value}"`);
e.currentTarget.value = "";
}
}
function handleFocus(e: React.FocusEvent<HTMLInputElement>) {
addLog("focus", `Input "${e.currentTarget.placeholder}" focado`);
}
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const formData = new FormData(e.currentTarget);
addLog("submit", `Formulário enviado com nome: "${formData.get("name")}"`);
e.currentTarget.reset();
}
return (
<div className="max-w-md space-y-4 rounded border p-4">
<div className="flex gap-2">
<button onClick={handleClick} className="rounded bg-blue-600 px-3 py-1 text-white">
Botão A
</button>
<button onClick={handleClick} className="rounded bg-green-600 px-3 py-1 text-white">
Botão B
</button>
</div>
<input
onKeyDown={handleKeyDown}
onFocus={handleFocus}
placeholder="Pressione Enter aqui..."
className="w-full rounded border px-3 py-1"
/>
<form onSubmit={handleSubmit} className="flex gap-2">
<input
name="name"
placeholder="Seu nome"
onFocus={handleFocus}
className="flex-1 rounded border px-3 py-1"
/>
<button type="submit" className="rounded bg-purple-600 px-3 py-1 text-white">
Enviar
</button>
</form>
<div className="max-h-48 overflow-y-auto rounded bg-gray-50 p-2">
<h3 className="mb-1 text-xs font-bold uppercase text-gray-500">Log de Eventos</h3>
{log.length === 0 && <p className="text-xs text-gray-400">Interaja com os controles acima...</p>}
{log.map(entry => (
<div key={entry.id} className="border-b py-1 text-xs">
<span className="font-mono font-bold text-blue-700">{entry.type}</span>{" "}
<span className="text-gray-600">{entry.detail}</span>{" "}
<span className="text-gray-400">{entry.timestamp}</span>
</div>
))}
</div>
</div>
);
}O que isso demonstra:
onClick, onKeyDown, onFocus, onSubmitReact.MouseEvent, React.KeyboardEvent, React.FocusEvent, React.FormEvente.preventDefault() para impedir que o envio do formulário recarregue a páginae.currentTarget para acessar o elemento ao qual o manipulador está anexadouseCallback para estabilizar uma função auxiliar chamada frequentementeSyntheticEvent que normaliza as diferenças entre navegadores.e.currentTarget é o elemento ao qual o manipulador está anexado; e.target é o elemento que originou o evento (pode ser um filho).| Prop do React | Tipo TypeScript | Evento Nativo |
|---|---|---|
onClick | React.MouseEvent<HTMLElement> | click |
onChange | React.ChangeEvent<HTMLInputElement> | input (React dispara a cada pressionamento de tecla) |
onSubmit | React.FormEvent<HTMLFormElement> | submit |
onKeyDown | React.KeyboardEvent<HTMLElement> | keydown |
onFocus | React.FocusEvent<HTMLElement> | focus |
onBlur | React.FocusEvent<HTMLElement> | blur |
onMouseEnter | React.MouseEvent<HTMLElement> | mouseenter |
onPointerDown | React.PointerEvent<HTMLElement> | pointerdown |
onDrag | React.DragEvent<HTMLElement> | drag |
Parar propagação:
function handleInner(e: React.MouseEvent) {
e.stopPropagation(); // impede que o onClick externo dispare
}
<div onClick={() => console.log("externo")}>
<button onClick={handleInner}>Clique em mim</button>
</div>Fase de captura:
// A variante "Capture" dispara de cima para baixo antes da fase de borbulhamento
<div onClickCapture={() => console.log("capturado primeiro")}>
<button onClick={() => console.log("borbulhado segundo")}>Clique</button>
</div>Acessando o evento nativo:
function handleClick(e: React.MouseEvent) {
const nativeEvent = e.nativeEvent; // o Evento DOM subjacente
console.log(nativeEvent instanceof MouseEvent); // true
}Dados personalizados via closures:
function handleDelete(itemId: string) {
setItems(prev => prev.filter(i => i.id !== itemId));
}
{items.map(item => (
<button key={item.id} onClick={() => handleDelete(item.id)}>
Excluir {item.name}
</button>
))}// Tipando uma prop de manipulador
interface SearchBarProps {
onSearch: (query: string) => void;
}
function SearchBar({ onSearch }: SearchBarProps) {
return (
<input
type="search"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
onSearch(e.target.value);
}}
/>
);
}
// Tipo de manipulador inline (útil para props de callback)
type ClickHandler = React.MouseEventHandler<HTMLButtonElement>;
// Tipo de elemento genérico
function logEvent<T extends HTMLElement>(e: React.SyntheticEvent<T>) {
console.log(e.currentTarget.tagName);
}Chamar a função em vez de passá-la - onClick={handleClick()} invoca a função durante a renderização, não no clique. Correção: Passe a referência: onClick={handleClick} ou envolva em uma seta: onClick={() => handleClick(arg)}.
Closures obsoletas em manipuladores - Um manipulador de eventos criado dentro de um componente captura o estado no momento da renderização. Se o estado for atualizado antes que o manipulador seja executado (raro), o manipulador verá valores antigos. Correção: Use useCallback com as dependências corretas, ou leia de um ref para obter os valores mais recentes.
onChange do React vs change do DOM - O onChange do React dispara a cada pressionamento de tecla (como o evento input do DOM), não no blur como o evento change nativo. Isso surpreende desenvolvedores vindos do JavaScript puro. Correção: Apenas saiba disso - é o comportamento pretendido.
Listeners de eventos passivos - O React não suporta a opção { passive: true } via props JSX. Para manipuladores de toque/roda onde você precisa de passive: false para chamar preventDefault(), você pode precisar de um addEventListener manual em um useEffect. Correção: Use useEffect + ref para anexar o listener nativo.
Funções de seta na renderização - onClick={() => doSomething(id)} cria uma nova função a cada renderização, o que pode anular React.memo. Correção: Para caminhos críticos (grandes listas), extraia o manipulador ou use useCallback. Para a maioria dos casos, está tudo bem - não otimize prematuramente.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
useEffect + addEventListener | Você precisa de listeners passivos, eventos em nível de janela, ou eventos que o React não envolve | O evento está em um elemento React específico (use o manipulador JSX) |
| Ações de Formulário (React 19) | Manipulando envios de formulário com ações de servidor | Formulários apenas do lado do cliente sem interação do servidor |
| Delegação baseada em Ref | Construindo uma biblioteca que precisa de controle bruto de eventos DOM | Código de aplicativo normal |
Um wrapper multiplataforma em torno do evento DOM nativo. O React cria um SyntheticEvent para cada manipulador de eventos, normalizando as diferenças entre navegadores. Acesse o evento nativo via e.nativeEvent se necessário.
e.currentTarget - o elemento ao qual o manipulador está anexadoe.target - o elemento que realmente disparou o evento (pode ser um filho)currentTarget ao ler atributos do elemento ao qual você anexou o manipuladorAdicionar () invoca a função durante a renderização e passa seu valor de retorno como manipulador. Passe a referência em vez disso: onClick={handleClick} ou envolva-o: onClick={() => handleClick(arg)}.
Envolva o manipulador em uma função de seta:
<button onClick={() => deleteItem(item.id)}>Excluir</button>Chame e.preventDefault() no manipulador onSubmit:
<form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>Use os tipos de evento do React com o genérico do elemento HTML:
function handleClick(e: React.MouseEvent<HTMLButtonElement>) { ... }
function handleChange(e: React.ChangeEvent<HTMLInputElement>) { ... }
function handleSubmit(e: React.FormEvent<HTMLFormElement>) { ... }Sim. O onChange do React se comporta como o evento input nativo, disparando a cada pressionamento de tecla - não no blur como o evento change nativo. Isso é por design para atualizações de formulário em tempo real.
Chame e.stopPropagation() no manipulador de eventos do filho. Para a fase de captura (de cima para baixo), use onClickCapture em vez de onClick.
Na maioria dos casos, não. A seta inline cria uma nova função a cada renderização, o que pode anular React.memo em componentes filhos. Otimize apenas com useCallback em caminhos críticos como grandes listas.
Use useEffect com addEventListener em window ou document:
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === "Escape") closeModal();
};
window.addEventListener("keydown", handler);
return () => window.removeEventListener("keydown", handler);
}, []);Digite-a como uma função que aceita os dados que você precisa:
interface Props {
onSearch: (query: string) => void;
}Ou use o tipo de manipulador integrado do React: React.MouseEventHandler<HTMLButtonElement>.
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥