Ashun's 技術駅 Ashun's 技術駅
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • Vue
  • 现代web布局
  • React
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 技术资源
  • 第一阶段

    • HTML
  • 第二阶段

    • JavaScript
  • 第三阶段

    • Vue
  • 第四阶段

    • 实战项目
  • 每周测试

    • 每周
  • 其他

    • Vue引入UI框架
    • Web前端面试
    • Vue3-resource
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 福利资源
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Ashun

前端界的小学生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • Vue
  • 现代web布局
  • React
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 技术资源
  • 第一阶段

    • HTML
  • 第二阶段

    • JavaScript
  • 第三阶段

    • Vue
  • 第四阶段

    • 实战项目
  • 每周测试

    • 每周
  • 其他

    • Vue引入UI框架
    • Web前端面试
    • Vue3-resource
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 福利资源
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • vue

  • vue3

  • es6

  • JavaScript

  • css

  • webpack

  • http

  • NodeJS

  • React

    • 01React
    • 02Real DOM_Virtual DOM
    • 03life cycle
    • 04state_props
    • 05super()_super(props)
    • 06setState
    • 07SyntheticEvent
      • 面试官:说说React的事件机制?
      • 一、是什么
        • 合成事件(SyntheticEvent)
      • 二、执行顺序
      • 三、总结
      • 参考文献
    • 08Binding events
    • 09Building components
    • 10communication
    • 11key
    • 12React refs
    • 13class_function component
    • 14controlled_Uncontrolled
    • 15High order components
    • 16React Hooks
    • 17import css
    • 18animation
    • 19redux
    • 20Redux Middleware
    • 21how to use redux
    • 22React Router
    • 23React Router model
    • 24immutable
    • 25render
    • 26improve_render
    • 27diff
    • 28Fiber
    • 29JSX to DOM
    • 30Improve performance
    • 31capture error
    • 32server side rendering
    • 33summary
  • git

  • linux

  • typescript

  • algorithm

  • applet

  • design

  • 《Web前端面试》
  • React
xugaoyi
2022-03-25
目录

07SyntheticEvent

# 面试官:说说React的事件机制?

# 一、是什么

React基于浏览器的事件机制自身实现了一套事件机制,包括事件注册、事件的合成、事件冒泡、事件派发等

在React中这套事件机制被称之为合成事件

# 合成事件(SyntheticEvent)

合成事件是 React模拟原生 DOM事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器

根据 W3C规范来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口,例如:

const button = <button onClick={handleClick}>按钮</button>
1

如果想要获得原生DOM事件,可以通过e.nativeEvent属性获取

const handleClick = (e) => console.log(e.nativeEvent);;
const button = <button onClick={handleClick}>按钮</button>
1
2

从上面可以看到React事件和原生事件也非常的相似,但也有一定的区别:

  • 事件名称命名方式不同
// 原生事件绑定方式
<button onclick="handleClick()">按钮命名</button>
      
// React 合成事件绑定方式
const button = <button onClick={handleClick}>按钮命名</button>
1
2
3
4
5
  • 事件处理函数书写不同
// 原生事件 事件处理函数写法
<button onclick="handleClick()">按钮命名</button>
      
// React 合成事件 事件处理函数写法
const button = <button onClick={handleClick}>按钮命名</button>
1
2
3
4
5

虽然onclick看似绑定到DOM元素上,但实际并不会把事件代理函数直接绑定到真实的节点上,而是把所有的事件绑定到结构的最外层,使用一个统一的事件去监听

这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。当组件挂载或卸载时,只是在这个统一的事件监听器上插入或删除一些对象

当事件发生时,首先被这个统一的事件监听器处理,然后在映射里找到真正的事件处理函数并调用。这样做简化了事件处理和回收机制,效率也有很大提升

# 二、执行顺序

关于React合成事件与原生事件执行顺序,可以看看下面一个例子:

import  React  from 'react';
class App extends React.Component{

  constructor(props) {
    super(props);
    this.parentRef = React.createRef();
    this.childRef = React.createRef();
  }
  componentDidMount() {
    console.log("React componentDidMount!");
    this.parentRef.current?.addEventListener("click", () => {
      console.log("原生事件:父元素 DOM 事件监听!");
    });
    this.childRef.current?.addEventListener("click", () => {
      console.log("原生事件:子元素 DOM 事件监听!");
    });
    document.addEventListener("click", (e) => {
      console.log("原生事件:document DOM 事件监听!");
    });
  }
  parentClickFun = () => {
    console.log("React 事件:父元素事件监听!");
  };
  childClickFun = () => {
    console.log("React 事件:子元素事件监听!");
  };
  render() {
    return (
      <div ref={this.parentRef} onClick={this.parentClickFun}>
        <div ref={this.childRef} onClick={this.childClickFun}>
          分析事件执行顺序
        </div>
      </div>
    );
  }
}
export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

输出顺序为:

原生事件:子元素 DOM 事件监听! 
原生事件:父元素 DOM 事件监听! 
React 事件:子元素事件监听! 
React 事件:父元素事件监听! 
原生事件:document DOM 事件监听! 
1
2
3
4
5

可以得出以下结论:

  • React 所有事件都挂载在 document 对象上
  • 当真实 DOM 元素触发事件,会冒泡到 document 对象后,再处理 React 事件
  • 所以会先执行原生事件,然后处理 React 事件
  • 最后真正执行 document 上挂载的事件

对应过程如图所示:

所以想要阻止不同时间段的冒泡行为,对应使用不同的方法,对应如下:

  • 阻止合成事件间的冒泡,用e.stopPropagation()

  • 阻止合成事件与最外层 document 上的事件间的冒泡,用e.nativeEvent.stopImmediatePropagation()

  • 阻止合成事件与除最外层document上的原生事件上的冒泡,通过判断e.target来避免

document.body.addEventListener('click', e => {   
    if (e.target && e.target.matches('div.code')) {  
        return;    
    }    
    this.setState({   active: false,    });   }); 
}
1
2
3
4
5
6

# 三、总结

React事件机制总结如下:

  • React 上注册的事件最终会绑定在document这个 DOM 上,而不是 React 组件对应的 DOM(减少内存开销就是因为所有的事件都绑定在 document 上,其他节点没有绑定事件)
  • React 自身实现了一套事件冒泡机制,所以这也就是为什么我们 event.stopPropagation()无效的原因。
  • React 通过队列的形式,从触发的组件向父组件回溯,然后调用他们 JSX 中定义的 callback
  • React 有一套自己的合成事件 SyntheticEvent

# 参考文献

  • https://zh-hans.reactjs.org/docs/events.html (opens new window)
  • https://segmentfault.com/a/1190000015725214?utm_source=sf-similar-article (opens new window)
  • https://segmentfault.com/a/1190000038251163 (opens new window)
编辑 (opens new window)
上次更新: 2023/08/06, 00:38:41
06setState
08Binding events

← 06setState 08Binding events→

最近更新
01
课件-react路由-V6
01-22
02
课件-国际化
01-22
03
课件-redux-toolkit
01-22
更多文章>
Theme by Vdoing | Copyright © 2019-2024 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式