事件处理
React 中事件命名采用驼峰式书写,并且需要传入一个函数作为事件处理函数。在函数组件中,一个事件的处理函数常常作为组件内的函数存在,在实际定义时可以使用关键字function
也可以直接定义一个匿名剪头函数。例如以下是一个最简单的响应<button>
元素点击事件的例子。
function Button(props) {
function handleClick() {
alert("Clicked!");
}
return <button onClick={handleClick}>{props.children}</button>;
}
但是这种function
中套function
的写法看起来属实比较怪,所以在实际使用中,常常都是使用匿名剪头函数来定义,例如:
function Button(props) {
const handleClick = () => {
alert("Clicked!");
};
return <button onClick={handleClick}>{props.children}</button>;
}
甚至还可以直接在onClick
的位置定义匿名函数。
function Button(props) {
return <button onClick={() => alert("Clicked!")}>{props.children}</button>;
}
优化事件处理函数定义
与useMemo
一样,在事件处理函数中如果访问了组件的 State 等内容,实际上也是一种开销。一种比较好的解决方法依旧是将事件处理函数缓存起来,等到它内部所使用的值发生变化的时候再重新渲染。
于是 React 中提供的另一个 Hook useCallback
就派上用场了,useCallback
可以在组件的多次渲染中缓存其所定义的函数。useCallback
的使用方法与useMemo
基本上一致,其接受的参数也是一个需要缓存的函数和一个dependencies
依赖项列表。
在大部分情况下,React是不会丢弃函数的缓存的,也就是说在应用刚开始开发的时候是没有必要直接使用useCallback
的,只有在某些计算过程变慢需要优化的时候才需要使用。如果应用中使用了虚拟列表等需要React丢弃函数缓存的功能,那么useCallback
就更没有用武之地了。
事件冒泡
事件冒泡通常是指事件在触发以后,沿着组件树向组件树的根节点传播。在传统 HTML DOM 编程中,我们常常使用e.stopPropagation()
来阻止事件继续冒泡。
但是如果需要在事件被阻止冒泡以后继续被捕获,那么就可以在组件树上使用事件带有Capture
后缀的版本来对其进行捕获。例如:
function Compo() {
return (
<div
onClickCapture={() => {
/* 将先于子元素的onClick处理执行 */
}}
>
<button onClick={() => e.stopPropagation()}>Click</button>
</div>
);
}
事件默认行为
在 HTML DOM 中,浏览器对一些事件是有默认处理行为的,例如<form>
的onSubmit
,会导致页面的刷新。要阻止这种默认行为,在 React 中的处理与 HTML DOM 中的处理一样,都是通过调用e.preventDefault()
来实现的。
事件类型
React 对于常见的 HTML 元素标签都提供了封装,同时也提供了相应事件的封装。在定义事件处理函数时,可以使用 React 提供的类型来接收和处理元素产生的事件。在 React 中经过包装的事件被称为合成事件,即SyntheticEvent<E>
类型对象。React 中的绝大多数事件类型都是从SyntheticEvent<E>
类型派生而来。
例如可以这样捕获input
产生的输入事件。
function Input() {
const [value, setValue] = useState<string | null>(null);
const handleInput = (e: InputEvent) => {
setValue(e.data);
};
return <input value={value} onChange={handleInput} />;
}
React 将 HTML DOM 的原生事件包装进了SyntheticEvent
的nativeEvent
属性中,在必要的时候可以通过这个属性来访问浏览器的原生事件。除了nativeEvent
以外,SyntheticEvent
类型还提供了以下标准属性可供使用。
bubbles
:布尔值,用于表示事件是否会冒泡传播。cancelable
:布尔值,用于表示事件是否可以被取消。currentTarget
:DOM 节点,用来获取当前节点在 React DOM 树中的位置。defaultPrevented
:布尔值,用来表示是否调用了preventDefault()
方法。eventPhase
:数字值,用来表示当前事件所处的阶段。isTrusted
:布尔值,用来返回事件是否由用户发起。target
:DOM 节点,用来返回事件发生的节点。timestamp
:数字值,用来返回事件发生的时间。
常用事件及其对应类型
以下事件监听属性适用于所有内置组件
事件监听属性 | 事件类型 | 触发时间 |
---|---|---|
onAnimationEnd | AnimationEvent | 在 CSS 动画完成时 |
onAnimationIteration | AnimationEvent | 在 CSS 动画的一次迭代结束时 |
onAnimationStart | AnimationEvent | 在 CSS 动画开始时 |
onAuxClick | AnimationEvent | 当指针设备上非主要指针按钮被点击时 |
onBeforeInput | InputEvent | 在可编辑元素的值被修改之前 |
onBlur | FocusEvent | 在元素失去焦点时 |
onClick | MouseEvent | 当指针设备上的主按钮被点击时 |
onCompositionStart | CompositionEvent | 当输入法编辑器开始新的组合会话时 |
onCompositionEnd | CompositionEvent | 当输入法编辑器完成或者取消组合会话时 |
onCompositionUpdate | CompositionEvent | 在输入法编辑器收到一个新的字符时 |
onContextMenu | MouseEvent | 在用户尝试打开上下文菜单时 |
onCopy | ClipboardEvent | 在用户尝试将一些内容复制到剪贴板时 |
onCut | ClipboardEvent | 在用户尝试将一些内容剪切到剪贴板时 |
onDoubleClick | MouseEvent | 在用户双击时 |
onDrag | DragEvent | 在用户拖拽某些元素时 |
onDragEnd | DragEvent | 在用户停止拖拽某些元素时 |
onDragOver | DragEvent | 在被拖动的元素进入指定放置目标时 |
onDragStart | DragEvent | 在用户开始拖拽元素时 |
onDrop | DragEvent | 在元素被拖放到有效的目的区域时 |
onFocus | FocusEvent | 在元素获得焦点时 |
onGotPointerCapture | PointerEvent | 当元素以变成方式捕获指针时 |
onKeyDown | KeyboardEvent | 当按键被按下时 |
onKeyUp | KeyboardEvent | 当按键被释放时 |
onLostPointerCapture | PointerEvent | 当元素停止捕获指针时 |
onMouseDown | MouseEvent | 当指针被按下时 |
onMouseEnter | MouseEvent | 当指针在元素内移动时 |
onMouseLeave | MouseEvent | 当指针移动到元素外部时 |
onMouseMove | MouseEvent | 当指针改变坐标时 |
onMouseOut | MouseEvent | 当指针移动到元素外部或者移动到子元素时 |
onMouseUp | MouseEvent | 当指针释放时 |
onPointerDown | PointerEvent | 当浏览器取消指针交互时 |
onPointerEnter | PointerEvent | 当指针在元素内移动时 |
onPointerLeave | PointerEvent | 当指针移动到元素外部时 |
onPointerMove | PointerEvent | 当指针改变坐标时 |
onPointerOut | PointerEvent | 当指针移动到元素外部时 |
onPointerUp | PointerEvent | 当指针不再活动时 |
onPaste | ClipboardEvent | 当用户尝试从剪贴板粘贴内容时 |
onScroll | Event | 当元素被滚动时 |
onSelect | Event | 当可编辑元素内部的选择更改后 |
onTouchCancel | TouchEvent | 当浏览器取消触摸交互时 |
onTouchEnd | TouchEvent | 当一个或者多个触摸点被移除时 |
onTouchMove | TouchEvent | 当一个或者多个触摸点发生移动时 |
onTouchStart | TouchEvent | 当一个或者多个触摸点被放置时 |
onTransitionEnd | TransitionEvent | 当 CSS 过度完成时 |
onWheel | WheelEvent | 当用户旋转滚轮时 |
以下事件监听属性适用于<form>
元素
事件监听属性 | 事件类型 | 触发时间 |
---|---|---|
onReset | Event | 当表单被重置时 |
onSubmit | Event | 当表单被提交时 |
以下事件监听属性适用于<dialog>
元素
事件监听属性 | 事件类型 | 触发时间 |
---|---|---|
onCancel | Event | 当用户尝试关闭对话框时 |
onClose | Event | 当对话框已经被关闭时 |
以下事件监听属性适用于<details>
元素
事件监听属性 | 事件类型 | 触发时间 |
---|---|---|
onToggle | Event | 当用户切换详细信息时 |
以下事件监听属性适用于<img>
、<iframe>
、<object>
、<embed>
、<link>
、SVG 中的<image>
元素
事件监听属性 | 事件类型 | 触发时间 |
---|---|---|
onLoad | Event | 当资源开始加载时 |
onError | Event | 当资源无法加载时 |
以下事件监听属性适用于<audio>
、<video>
元素
事件监听属性 | 事件类型 | 触发时间 |
---|---|---|
onAbort | Event | 当资源没有完全加载时 |
onCanPlay | Event | 当有足够的数据可以开始播放但没有缓冲到结束时 |
onCanPlayThrough | Event | 当有足够的数据且可以播放到结束时 |
onDurationChange | Event | 当媒体持续事件更新时 |
onEmptied | Event | 当媒体变为空时 |
onEncrypted | Event | 当浏览器遇到加密媒体时 |
onEnded | Event | 当因为没有剩余内容可以播放而停止时 |
onError | Event | 当资源无法播放时 |
onLoadedData | Event | 在当前播放帧已被加载时 |
onLoadedMetadata | Event | 当元数据加载完成时 |
onLoadStart | Event | 当浏览器开始加载资源时 |
onPause | Event | 当媒体暂停时 |
onPlay | Event | 当媒体不再暂停时 |
onPlaying | Event | 当媒体开始或者重新开始播放时 |
onProgress | Event | 在资源加载时定期触发 |
onRateChange | Event | 当播放帧率改变时 |
onResize | Event | 当视频大小发生改变时 |
onSeeked | Event | 当搜索操作完成时 |
onSeeking | Event | 当搜索操作开始时 |
onStalled | Event | 当浏览器等待数据时 |
onSuspend | Event | 当资源加载被暂停时 |
onTimeUpdate | Event | 当播放时间更新时 |
onVolumeChange | Event | 当音量发生变化时 |
onWaiting | Event | 当临时缺少数据而播放停止时 |