React事件处理机制详解

ops/2024/11/23 7:14:57/

​🌈个人主页:前端青山
🔥系列专栏:React篇
🔖人终将被年少不可得之物困其一生

依旧青山,本期给大家带来React篇专栏内容:React-

前言

前端开发中,事件处理是构建交互式用户界面的关键部分。React 作为一个流行的 JavaScript 库,提供了丰富的事件处理机制,使得开发者能够更高效地管理事件。本文将详细介绍 React 中事件处理的基本概念,包括 ES5 和 ES6 语法的事件绑定方法,并深入探讨 React 合成事件的特点及其内部机制。

目录

前言

1 ES5语法绑定事件

1.1 无参数的绑定

1.1.1 方法一

1.1.2 方法二

1.1.2 有参数的绑定

1.2 ES6语法绑定事件

1.2.1 无参数绑定

1.2.1.1 方法一

1.2.1.2 方法二

1.2.2 有参数绑定

1.2.2.1 方法一

1.2.2.2 方法二

1.3 合成事件的特点

1.3.1 事件机制

1.3.2 对合成事件的理解

1.3.3 事件机制的流程

1、事件注册

2、事件存储

3、事件执行

1.3.4 合成事件、原生事件之间的冒泡执行关系

总结

React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。

  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

1 ES5语法绑定事件

1.1 无参数的绑定

1.1.1 方法一
  • 定义函数

javascript">handleClick(e) { // e - 事件对象e.preventDefault();// doSomething ...
}
  • constructor 中绑定函数执行上下文

javascript">this.handleClick = this.handleClick.bind(this);
  • jsx中调用

javascript"><button onClick={this.hanleClick} />
1.1.2 方法二
  • 定义函数

javascript">handleClick(e) { // e - 事件对象e.preventDefault();// doSomething ...
}
  • jsx 中调用

javascript"><button onClick={this.hanleClick.bind(this)} />

1.1.2 有参数的绑定

  • 定义函数

javascript">handleClick(param1, param2, e) {e.preventDefault();// do something ...
}

注意此时无论多少个参数, e 一定放在最后

  • jsx 中调用

javascript"><button onClick={this.hanleClick.bind(this, 'x', 'xx')} />

src/index.js

javascript">import React from 'react'
import ReactDOM  from 'react-dom/client'
​
// 引入时,后缀名可以省略,可以在webpack中配置
// import App from './01-App-parent-child'
// import App from './02-App-parent-child-value'
// import App from './03-App-parent-child-value-default'
// import App from './04-App-parent-child-value-default-type'
// import App from './05-App-props-children'
// import App from './06-App-mutiple-props-children'
// import App from './07-App-mouse-tracker'
// import App from './08-App-render-props'
// import App from './09-App-state-es6'
// import App from './10-App-state-es7'
// import App from './11-App-setState-function'
// import App from './12-App-setState-object'
// import App from './13-App-setState-callback'
// import App from './14-App-LifeCycle'
import App from './15-App-handler-es5'
​
const root = ReactDOM.createRoot(document.getElementById('root'))
​
root.render(<App root={ root }/>)
​

src/15-App-handler-es5.jsx

javascript">import React, { Component } from 'react';
​
class App extends Component {constructor (props) {super(props)// 中绑定函数执行上下文this.clickHandler1Fn = this.clickHandler1.bind(this)}clickHandler1 (event) { // 构造函数中改变this指向 不推荐 --- 无法实现传递参数目标console.log(this)  // undefined  ==构造函数中改变this指向==>  App实例console.log(event) // SyntheticBaseEvent合成事件   js原生 PointerEvent}
​clickHandler2 (event) { // 推荐 ---- 可以传递参数console.log(this) // undefined  ===jsx代码中改变了this指向===> App实例console.log(event)}
​// 无论有多少个参数,记住,事件对象始终为最后一个参数clickHandler3 (params1, params2, params3, event) {console.log(params1)console.log(params2)console.log(params3)console.log(event)}render() {return (<div><h1>es5绑定事件以及传递参数</h1><button onClick={ this.clickHandler1Fn }>点击-绑定事件方法1</button><button onClick={ this.clickHandler2.bind(this) }>点击-绑定事件方法2 - 推荐</button><button onClick={ this.clickHandler3.bind(this, 'a', 'b', 'c') }>点击-传递参数</button></div>);}
}
​
export default App;

1.2 ES6语法绑定事件

1.2.1 无参数绑定

1.2.1.1 方法一
  • 定义函数

javascript">handleClick = (e) => {e.preventDefault();// do something ...
}
  • jsx中调用

javascript"><button onClick={this.hanleClick} />

比起 es 5 中的无参数函数的绑定调用, es 6 不需要使用 bind 函数;

1.2.1.2 方法二

jsx中定义箭头函数

javascript"><button onClick={ () => {}} />

1.2.2 有参数绑定

1.2.2.1 方法一
  • 定义函数

javascript">handleClick = (param1, e) => {e.preventDefault();// do something ...
}
  • jsx调用

javascript"><button onClick={this.hanleClick.bind(this, 'x')} />

有参数时,在绑定时依然要使用 bind; 并且参数一定要传,不然仍然存在 this 指向错误问题;

1.2.2.2 方法二
  • 定义函数

javascript">handleClick = (param1, e) => {// do something ...
}
  • jsx调用

javascript"><button onClick={() => this.handleClick('c')} />
// 如果需要对 event 对象进行处理的话,需要写成下面的格式
<button onClick={(e) => this.handleClick('c', e)} />

src/index.js

javascript">import React from 'react'
import ReactDOM  from 'react-dom/client'
​
// 引入时,后缀名可以省略,可以在webpack中配置
// import App from './01-App-parent-child'
// import App from './02-App-parent-child-value'
// import App from './03-App-parent-child-value-default'
// import App from './04-App-parent-child-value-default-type'
// import App from './05-App-props-children'
// import App from './06-App-mutiple-props-children'
// import App from './07-App-mouse-tracker'
// import App from './08-App-render-props'
// import App from './09-App-state-es6'
// import App from './10-App-state-es7'
// import App from './11-App-setState-function'
// import App from './12-App-setState-object'
// import App from './13-App-setState-callback'
// import App from './14-App-LifeCycle'
// import App from './15-App-handler-es5'
import App from './16-App-handler-es6'
​
const root = ReactDOM.createRoot(document.getElementById('root'))
​
root.render(<App root={ root }/>)
​

src/16-App-handler-es6.jsx

javascript">import React, { Component } from 'react';
​
class App extends Component {clickHandler1 = (event) => { // 类中定义箭头函数console.log(this)console.log(event)}
​clickHandler3 = (params, event) => {console.log(params)console.log(this)console.log(event)}
​clickHandler4 = (params1, params2, event) => {console.log(params1)console.log(params2)console.log(this)console.log(event)}render() {return (<div><h1>es6绑定事件以及传递参数</h1><button onClick={ this.clickHandler1 }>点击-绑定事件方法1</button><button onClick={ (event) => { // jsx中写箭头函数console.log(this)console.log(event)} }>点击-绑定事件方法2</button><button onClick={ this.clickHandler3.bind(this, '参数') }>传递参数1</button><button onClick={ (event) => this.clickHandler4('aaa', 'bbb', event) }>传递参数2</button></div>);}
}
​
export default App;

1.3 合成事件的特点

1.3.1 事件机制

  • react自身实现了一套事件机制,包括事件的注册、事件的存储、事件的合成及执行等。

  • react 的所有事件并没有绑定到具体的dom节点上而是绑定在了document 上,然后由统一的事件处理程序来派发执行。

  • 通过这种处理,减少了事件注册的次数,另外react还在事件合成过程中,对不同浏览器的事件进行了封装处理,抹平浏览器之间的事件差异。

1.3.2 对合成事件的理解

(1)对原生事件的封装

react会根据原生事件类型来使用不同的合成事件对象,比如: 聚焦合成事件对象SyntheticFoucsEvent(合成事件对象:SyntheticEventreact合成事件的基类,定义了合成事件的基础公共属性和方法。合成事件对象就是在该基类上创建的)

(2)不同浏览器事件兼容的处理

在对事件进行合成时,react针对不同的浏览器,也进行了事件的兼容处理

1.3.3 事件机制的流程

1、事件注册

在组件挂载阶段,根据组件内声明的事件类型-onclickonchange 等,给 document 上添加事件 -addEventListener,并指定统一的事件处理程序 dispatchEvent

2、事件存储

完成事件注册后,将react dom ,事件类型,事件处理函数fn放入数组存储,组件挂载完成后,经过遍历把事件处理函数存储到 listenerBank(一个对象)中,缓存起来,为了在触发事件的时候可以查找到对应的事件处理方法去执行。

开始事件的存储,在react 里所有事件的触发都是通过 dispatchEvent方法统一进行派发的,而不是在注册的时候直接注册声明的回调,来看下如何存储的 。 react 把所有的事件和事件类型以及react 组件进行关联,把这个关系保存在了一个map里,也就是一个对象里(键值对),然后在事件触发的时候去根据当前的 组件id和 事件类型查找到对应的 事件fn

3、事件执行

1、进入统一的事件分发函数(dispatchEvent) 2、结合原生事件找到当前节点对应的ReactDOMComponent对象 3、开始 事件的合成

  • 根据当前事件类型生成指定的合成对象

  • 封装原生事件和冒泡机制

  • listenerBank事件池中查找事件回调并合成到 event(合成事件结束)

4.处理合成事件内的回调事件(事件触发完成 end)

1.3.4 合成事件、原生事件之间的冒泡执行关系

结论:

  • 原生事件阻止冒泡肯定会阻止合成事件的触发。

  • 合成事件的阻止冒泡不会影响原生事件。

原因:

  • 浏览器事件的执行需要经过三个阶段,捕获阶段-目标元素阶段-冒泡阶段

节点上的原生事件的执行是在目标阶段,然而合成事件的执行是在冒泡阶段,所以原生事件会先合成事件执行,然后再往父节点冒泡,所以原生事件阻止冒泡会阻止合成事件的触发,而合成事件的阻止冒泡不会影响原生事件

总结

本文详细介绍了 React 中事件处理的两种主要语法:ES5 和 ES6。通过对比这两种语法的事件绑定方法,我们了解到 ES6 的箭头函数在事件处理中的优势,特别是在处理 this 指向问题时更加简洁和直观。此外,文章还深入探讨了 React 合成事件的特点,包括事件机制的流程、事件注册、事件存储和事件执行等环节。通过这些内容,开发者可以更好地理解 React 事件处理的内部机制,从而在实际开发中更加灵活地运用这些知识。


http://www.ppmy.cn/ops/136008.html

相关文章

C语言基础学习:抽象数据类型(ADT)

基础概念 抽象数据类型&#xff08;ADT&#xff09;是一种数据类型&#xff0c;它定义了一组数据以及可以在这组数据上执行的操作&#xff0c;但隐藏了数据的具体存储方式和实现细节。在C语言中&#xff0c;抽象数据类型&#xff08;ADT&#xff09;是一种非常重要的概念&…

第六届国际科技创新学术交流大会(IAECST 2024)暨第四届物流系统与交通运输国际学术会议(LSTT 2024)

重要信息 会议官网&#xff1a;www.lstt.org 大会时间&#xff1a;2024年12月6-8日 大会地点&#xff1a;中国-广州 大会简介 第六届国际科技创新学术交流大会暨第四届物流系统与交通运输国际学术会议&#xff08;LSTT 2024&#xff09;将于2024年12月6-8日在广州举办&…

大语言模型---ReLU函数的计算过程及其函数介绍

文章目录 1. 概要2. ReLU定义 1. 概要 **ReLU 作用&#xff1a;**主要用于为神经网络引入非线性能力&#xff0c;作用是将输入中的整数保留原值&#xff0c;负数置为 0。 从而在层与层之间引入非线性&#xff0c;使神经网络能够拟合复杂的非线性关系。 **ReLU使用场景&#xf…

什么是事务?事务有哪些特性?

在数据库管理中&#xff0c;事务是一个核心概念&#xff0c;它确保了数据操作的完整性和一致性。本文将探讨事务的定义及其四大特性。 一、事务的定义 事务是数据库操作的最小工作单元&#xff0c;是作为单个逻辑工作单元执行的一系列操作。这些操作作为一个整体一起向系统提…

AI技术在电商行业中的应用面临哪些挑战?

AI技术在电商行业的应用尽管具有巨大潜力&#xff0c;但也面临以下主要挑战&#xff1a; 挑战 1. 数据质量与隐私问题 数据量与质量不均&#xff1a;电商平台需要大量高质量数据来训练AI模型&#xff0c;但数据可能不完整、不准确&#xff0c;或存在偏差&#xff0c;影响AI预…

实验四:构建园区网(OSPF 动态路由)

目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验步骤 1、在 eNSP 中部署网络 2、设计全网 IP 地址 3、配置二层交换机 4、配置路由交换机并测试通信 5、配置路由接口地址 6、配置 OSPF 动态路由&#xff0c;实现全网互通 一、实验简介 使用路由…

机器学习基础06

目录 1.梯度下降 1.1梯度下降概念 1.2梯度下降公式 1.3学习率 1.4实现梯度下降 1.5API 1.5.1随机梯度下降SGD 1.5.2小批量梯度下降MBGD 1.6梯度下降优化 2.欠拟合过拟合 2.1欠拟合 2.2过拟合 2.3正则化 2.3.1L1正则项&#xff08;曼哈顿距离&#xff09; 2.3.2…

蓝桥杯每日真题 - 第19天

题目&#xff1a;&#xff08;费用报销&#xff09; 题目描述&#xff08;13届 C&C B组F题&#xff09; 解题思路&#xff1a; 1. 问题抽象 本问题可以看作一个限制条件较多的优化问题&#xff0c;核心是如何在金额和时间约束下选择最优方案&#xff1a; 动态规划是理想…