Melhores Práticas de Eventos do React
Um resumo condensado das 25 melhores práticas mais importantes extraídas de cada página desta seção.
Busque em todas as páginas da documentação
Um resumo condensado das 25 melhores práticas mais importantes extraídas de cada página desta seção.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
e.clipboardData.setData(...) em onCopy sem e.preventDefault() permite que o navegador sobrescreva silenciosamente sua carga útil personalizada com a seleção; sempre previna o padrão primeiro, depois escreva todos os formatos que desejar (por exemplo, text/plain e text/html).<div> e outros elementos não-input nunca recebem onPaste a menos que mantenham o foco, então adicione tabIndex={0} (ou -1) mais um estilo de foco seguro contra contorno para que zonas de paste personalizadas realmente funcionem.onDragOver chame e.preventDefault(); sem isso, o cursor mostra "não permitido" e onDrop nunca dispara, que é o bug mais comum de drag HTML5.dataTransfer.getData() retorna "" durante dragover/dragenter; apenas dataTransfer.types é inspecionável durante o drag, então use feature-gate nos tipos e leia a carga útil em onDrop.dnd-kit ou construa lógica personalizada de eventos de ponteiro quando o suporte a toque for importante.e.currentTarget.contains(e.relatedTarget as Node) para dizer "o foco se moveu entre filhos" de "o foco realmente saiu do contêiner" - onBlur={e => { if (!e.currentTarget.contains(e.relatedTarget)) closeDropdown() }} - lembre-se que relatedTarget é null quando o foco sai do documento completamente.focus/blur nativos, onFocus e onBlur do React são ligados a focusin/focusout e borbulham na árvore - então um pai vê cada mudança de foco de filho, e misturar manipuladores do React com addEventListener("focus", …) produz comportamento inconsistente.onBlur antes que um clique em sua opção seja registrado, troque o manipulador da opção para onMouseDown + e.preventDefault() para que o clique seja capturado antes que o foco mude.onChange do React mapeia para o evento input nativo, não change nativo, então ele dispara a cada pressionamento de tecla em vez de no blur; use onBlur (ou useDeferredValue) quando você genuinamente quiser semântica de commit com debounce.value em <input type="file">, então leia os arquivos através de onChange - onChange={e => setFile(e.target.files?.[0])} - e um ref, e nunca tente controlar o valor; limpar significa atribuir "" diretamente ao nó DOM via inputRef.current!.value = "".action de formulário do React 19 mais useActionState ignora onSubmit completamente (nenhum preventDefault necessário); combinar os dois no mesmo formulário produz um duplo manuseio confuso, então escolha um modelo por formulário.onKeyPress é obsoleto e nunca dispara para Escape, setas, Tab, ou modificadores; use onKeyDown para toda interação de teclado incluindo atalhos e navegação acessível de widgets.e.key é consciente do layout e modificadores ("A" com Shift) e é o que você quer para atalhos; e.code é a posição física ("KeyA") e é o que você quer para jogos estilo WASD onde o layout não deve importar.onKeyDown dispara continuamente enquanto uma tecla é pressionada com e.repeat === true, então retorne cedo em repetição - onKeyDown={e => { if (e.repeat) return; sendMessage() }} - para manipuladores caros como chamadas de rede ou transições de estado que você só quer uma vez por pressionamento.onTransitionEnd dispara uma vez por propriedade CSS animada, então uma transição em opacity e transform despacha duas vezes; proteja manipuladores: onTransitionEnd={e => { if (e.propertyName !== "opacity") return; onFadeComplete() }}.onTimeUpdate a aproximadamente quatro vezes por segundo, o que é muito grosseiro para scrubs de progresso ou destaques de waveform - direcione esses a partir de requestAnimationFrame lendo video.currentTime em vez disso.onMouseEnter/onMouseLeave disparam apenas no elemento exato, enquanto onMouseOver/onMouseOut borbulham e disparam novamente em cada filho que cruza; misturá-los causa flicker em regiões de hover aninhadas, então escolha enter/leave para UIs de hover.onMouseMove dispara em cada pixel de movimento e pode disparar tempestades de re-renderização; escreva em um ref e agende atualizações com requestAnimationFrame, ou aceite que atualizações de estado brutas irão derrubar a taxa de quadros.onPointerDown - onPointerDown={e => e.currentTarget.setPointerCapture(e.pointerId)} - chamá-lo depois ou de um efeito é tarde demais para redirecionar eventos subsequentes.touch-action: none no elemento arrastável para que o navegador ceda o gesto aos seus manipuladores de ponteiro.onPointerLeave, então use onGotPointerCapture/onLostPointerCapture para rastrear o estado real de captura em vez de inferi-lo de eventos de entrada/saída.onScroll na raiz ou no body só dispara quando esse elemento em si tem uma barra de rolagem, então use useEffect - useEffect(() => { const h = () => {}; window.addEventListener("scroll", h, { passive: true }); return () => window.removeEventListener("scroll", h); }, []) - e sempre passe { passive: true } para manter a rolagem do thread compositor rápida.IntersectionObserver roda fora da thread principal e é muito mais barato do que computar a visibilidade a partir de matemática de onScroll; use-o para lazy-load, scroll infinito e lógica do tipo "passou do cabeçalho"; e proteja com isIntersecting pois ele dispara imediatamente ao observar.onTouchEnd as listas touches e targetTouches estão vazias (o dedo que disparou o evento já levantou), então sempre leia e.changedTouches[0] para obter a posição final e converta com Array.from(e.changedTouches) pois TouchList não é um array.e.preventDefault() dentro de onTouchMove falha silenciosamente; anexe um listener não-passivo via ref.addEventListener("touchmove", h, { passive: false }) ou aplique touch-action: none e deixe o CSS bloquear o gesto.Revisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥