Las Mejores Prácticas de React Events
Un resumen condensado de las 25 mejores prácticas más importantes extraídas de cada página en esta sección.
Busca en todas las páginas de la documentación
Un resumen condensado de las 25 mejores prácticas más importantes extraídas de cada página en esta sección.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
e.clipboardData.setData(...) en onCopy sin e.preventDefault() permite que el navegador sobrescriba silenciosamente tu payload personalizado con la selección; siempre previene el predeterminado primero, luego escribe cada formato que quieras (p. ej., text/plain y text/html).<div> y otros elementos que no son de entrada nunca reciben onPaste a menos que tengan foco, así que agrega tabIndex={0} (o -1) más un estilo de foco seguro para contorno para que las zonas de paste personalizado realmente funcionen.onDragOver llama a e.preventDefault(); sin él el cursor muestra "no permitido" y onDrop nunca se dispara, que es el error HTML5 drag más común.dataTransfer.getData() devuelve "" durante dragover/dragenter; solo dataTransfer.types es inspeccionar durante el drag, así que feature-gate en types y lee el payload en onDrop.dnd-kit o construye lógica de pointer-event personalizada cuando el soporte touch importa.e.currentTarget.contains(e.relatedTarget as Node) para diferenciar "el foco se movió entre children" de "el foco realmente salió del contenedor" - onBlur={e => { if (!e.currentTarget.contains(e.relatedTarget)) closeDropdown() }} - recuerda que relatedTarget es null cuando el foco sale del documento completamente.focus/blur nativo, onFocus y onBlur de React están cableados a focusin/focusout y hacen burbuja hacia arriba en el árbol - así que un padre ve cada cambio de foco de hijo, y mezclar manejadores React con addEventListener("focus", …) produce un comportamiento inconsistente.onBlur antes de que un clic en su opción se registre, cambia el manejador de la opción a onMouseDown + e.preventDefault() para que el clic sea capturado antes de que el foco se mueva.onChange de React se asigna al evento nativo input, no a change nativo, así que se dispara en cada pulsación de tecla en lugar de en blur; usa onBlur (o useDeferredValue) cuando genuinamente quieres semántica de commit con debounce.value en <input type="file">, así que lee archivos a través de onChange - onChange={e => setFile(e.target.files?.[0])} - y un ref, y nunca intentes controlar el valor; limpiar significa asignar "" al nodo del DOM directamente vía inputRef.current!.value = "".action prop del formulario de React 19 más useActionState evita onSubmit completamente (sin necesidad de preventDefault); combinar los dos en el mismo formulario produce un double-handling confuso, así que elige un modelo por formulario.onKeyPress está deprecated y nunca se dispara para Escape, arrows, Tab, o modificadores; usa onKeyDown para cada interacción de teclado incluyendo atajos y navegación de widget accesible.e.key es consciente del layout y modificador ("A" con Shift) y es lo que quieres para atajos; e.code es la posición física ("KeyA") y es lo que quieres para juegos al estilo WASD donde el layout no debe importar.onKeyDown se dispara continuamente mientras una tecla se mantiene presionada con e.repeat === true, así que early-return en repeat - onKeyDown={e => { if (e.repeat) return; sendMessage() }} - para manejadores costosos como llamadas de red o transiciones de estado que solo quieres una vez por pulsación.onTransitionEnd se dispara una vez por cada propiedad CSS animada, así que una transición en opacity y transform se dispara dos veces; protege manejadores: onTransitionEnd={e => { if (e.propertyName !== "opacity") return; onFadeComplete() }}.onTimeUpdate a aproximadamente cuatro veces por segundo, que es demasiado grueso para scrubs de progreso o highlights de waveform - dirígelos desde requestAnimationFrame leyendo video.currentTime en su lugar.onMouseEnter/onMouseLeave se disparan solo en el elemento exacto, mientras onMouseOver/onMouseOut hacen burbuja y se disparan nuevamente en cada cruce de hijo; mezclarlos causa flicker en regiones hover anidadas, así que elige enter/leave para UIs hover.onMouseMove se dispara en cada píxel de movimiento y puede desencadenar re-render storms; escribe a un ref y programa actualizaciones con requestAnimationFrame, o acepta que las actualizaciones raw de state afectarán la frame rate.onPointerDown - onPointerDown={e => e.currentTarget.setPointerCapture(e.pointerId)} - llamarlo después o desde un effect es demasiado tarde para redirigir eventos posteriores.touch-action: none en el elemento arrastrable para que el navegador ceda el gesto a tus manejadores pointer.onPointerLeave, así que usa onGotPointerCapture/onLostPointerCapture para rastrear el estado de captura real en lugar de inferirlo de eventos enter/leave.onScroll en el root o body solo se dispara cuando ese elemento en sí tiene un scrollbar, así que usa useEffect - useEffect(() => { const h = () => {}; window.addEventListener("scroll", h, { passive: true }); return () => window.removeEventListener("scroll", h); }, []) - y siempre pasa { passive: true } para mantener el scrolling de hilo compositor rápido.IntersectionObserver se ejecuta fuera del hilo principal y es mucho más barato que computar visibilidad de matemáticas onScroll; úsalo para lazy-load, infinite scroll, y lógica de estilo "scrolled past header", y protégete con isIntersecting ya que se dispara inmediatamente en observe.onTouchEnd las listas touches y targetTouches están vacías (el dedo que disparó el evento ya ha levantado), así que siempre lee e.changedTouches[0] para obtener la posición final y convierte con Array.from(e.changedTouches) ya que TouchList no es un array.e.preventDefault() dentro de onTouchMove falla silenciosamente; ya sea adjunta un oyente no-pasivo vía ref.addEventListener("touchmove", h, { passive: false }) o aplica touch-action: none y deja que CSS bloquee el gesto.Revisado por Chris St. John·Última actualización: 16 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥