标准答案

  1. React 事件通过 JSX 属性绑定,例如 onClick、onChange,回调拿到的是 React 合成事件对象。
  2. 合成事件屏蔽了一些浏览器差异,并让 React 可以在自己的事件系统中调度更新。
  3. React 通常会把事件委托到根容器上处理,而不是每个 DOM 节点都直接绑定原生监听。
  4. 合成事件的冒泡路径和原生 DOM 事件大体一致,但 Portal 等场景下会按 React 组件树传播。
  5. 需要接入第三方库、监听 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 组件树冒泡。

作者信息