标准答案
- React 事件通过 JSX 属性绑定,例如 onClick、onChange,回调拿到的是 React 合成事件对象。
- 合成事件屏蔽了一些浏览器差异,并让 React 可以在自己的事件系统中调度更新。
- React 通常会把事件委托到根容器上处理,而不是每个 DOM 节点都直接绑定原生监听。
- 合成事件的冒泡路径和原生 DOM 事件大体一致,但 Portal 等场景下会按 React 组件树传播。
- 需要接入第三方库、监听 window/document 或捕获 React 不支持的事件时,可以使用原生 addEventListener。
题目解析
这道题可以从绑定方式、事件对象、委托位置和传播路径四个角度回答。
React 17 之后事件委托位置从 document 调整到根容器,这会影响多 React 根或渐进接入场景。
不要把合成事件和原生事件混用得太随意,否则 stopPropagation、事件顺序和清理逻辑容易变复杂。
代码示例
下面同时展示 React 合成事件和原生事件监听。
TSX
function ClickPanel() {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const element = ref.current
if (!element) return
function handleNativeClick() {
console.log('native click')
}
element.addEventListener('click', handleNativeClick)
return () => element.removeEventListener('click', handleNativeClick)
}, [])
return (
<div ref={ref} onClick={() => console.log('react click')}>
点击
</div>
)
}常见误区
- 把 React 的 onClick 当成简单的 addEventListener 语法糖。
- 混用原生事件和合成事件时,没有处理解绑和传播顺序。
- 不知道 Portal 中合成事件会沿 React 组件树冒泡。