- 原生事件是浏览器层面的事件
- 自定义事件是纯组件实现的一种机制
首先,是不是所有的回调函数都需要用useCallback进行封装呢?
- 是否需要使用useCallback和函数复杂度没有必然关系,而是和回调函数绑定到哪个组件有关。这是为了避免因组件属性变化而导致不必要的重新渲染。
对于原生的DOM节点,如button、input等,我们是不用担心重新渲染的。所以,如果事件处理函数是传递给原生节点,那么可以不写callback。
但如果使用的是自定义组件,或者一些UI框架的组件,那么回调函数还都应该用useCallback进行封装。
-
react中处理事件的原理(浏览器的冒泡模型)
- 由于虚拟DOM的存在,react中即使绑定一个事件到原生DOM节点上,事件也并不是绑定到对应节点上,而是所有事件都绑定在根节点上。然后由react统一监听和管理,获取事件再分发到具体DOM节点上
- React17之前,所有的事件都是绑定到document上;而从React17之后,所有的事件都绑定在整个App上的根节点上,主要是为了以后页面上可能存在多版本React的考虑
React这么做的原因主要有两个:
- 虚拟DOM render的时候,有可能还没有真实的render到页面上,这时无法绑定事件到节点上
- React可以屏蔽底层事件的细节,避免浏览器的兼容性问题。即支持以前在原生DOM上定义事件的方式,提供了一致性的API
-
创建自定义事件
- 本质是组件自己的行为,是一种函数回调
- 而原生事件是浏览器机制
例子,用Hooks封装键盘事件
Hook具备绑定任何数据源的能力
import { useEffect, useState } from 'react'
const useKeyPress = (domNode = document.body) => {
const [key,setKey] = useState(null)
useEffect(() => {
const handlePress = (evt) => {
setKey(evt.keyCode)
}
domNode.addEventListener('keyPress', handlePress)
return () => {
domNode.removeEventListener('keyPress',handlePress)
}
}, [domNode])
return key
}
使用:
function useKeyPressExample() {
// 使用自定义的hook
const key = useKeyPress()
return (
<div>
<h1>Please key press</h1>
<label>Key pressed: {key || "N/A"}</label>
</div>
)
}