React 合成事件和 JavaScript 事件有什么区别?

开发 前端
五一前帮一个同学做模拟面试的时候,聊到了 React 的合成事件和 JavaScript 原生事件的差异性问题。我发现很多 React 技术栈的同学对这一方面好像理解的并不清楚,所以今天咱们这篇文章主要就来说下这个问题。

五一前帮一个同学做模拟面试的时候,聊到了 React 的合成事件和 JavaScript 原生事件的差异性问题。我发现很多 React 技术栈的同学对这一方面好像理解的并不清楚,所以今天咱们这篇文章主要就来说下这个问题。

1.设计理念

React合成事件 封装 了原生浏览器事件,提供了统一的API接口,使得开发者无论浏览器环境如何都可以用相同的方式处理事件。这种方法的主要目的是:确保跨浏览器的一致性并与 React 的声明式编程模型和生命周期集成。

JavaScript 中的事件处理程序 由浏览器直接提供,与特定的浏览器行为密切相关。不同的浏览器可能有不同的实现和支持级别。

2.浏览器兼容性

React 合成事件处理所有浏览器兼容性问题,为开发人员提供一个干净、一致的事件处理接口。

例如:它标准化了不同浏览器之间的事件行为,以事件冒泡和默认行为为例,咱们来看下它的实现:

// 构造器定义,接收事件配置、目标实例、本地事件和事件目标作为参数
function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
  this.dispatchConfig = dispatchConfig; // 存储事件的配置信息,例如事件类型
  this._targetInst = targetInst; //存储触发事件的组件实例
  this.nativeEvent = nativeEvent; // 存储本机浏览器事件对象
  this.target = nativeEventTarget; // 存储事件的原生目标,即事件最初发生的多姆元素
  this.currentTarget = null; // 处理事件的当前多姆元素将在事件处理期间设置
}

// SyneticEvents的原型对象,定义所有实例共享的方法
SyntheticEvent.prototype = {
  // Method to prevent the default event behavior
  preventDefault: function() {
    this.defaultPrevented = true; // 标志着事件的默认行为已被阻止
    const event = this.nativeEvent; // 获取本地事件对象
    if (!event) {
      return; // 如果没有本地事件对象,则直接返回
    }

    // 如果本机事件对象支持preventAlert方法,请调用它以防止默认行为
    if (event.preventDefault) {
      event.preventDefault();
    } else if (typeof event.returnValue !== 'undefined') { // 与IE8及以下版本兼容
      event.returnValue = false; // 在较旧的IE浏览器中,使用returnValue= true来防止默认行为
    }
  },
  
  // 阻止事件进一步传播的方法
  stopPropagation: function() {
    const event = this.nativeEvent; // 获取本地事件对象
    if (!event) {
      return; // 如果没有本地事件对象,则直接返回
    }

    // 如果本机事件对象支持stopPropagation方法,请调用它来停止事件冒泡
    if (event.stopPropagation) {
      event.stopPropagation();
    } else if (typeof event.cancelBubble !== 'undefined') { // 与IE8及以下版本兼容
      event.cancelBubble = true; // 在较旧的IE浏览器中,使用cancelBubble=true来停止事件冒泡
    }
  },
  // ...
};

3.性能优化

React 合成事件使用 事件池 来提高性能,即:重(chong)用事件对象。

这意味着:事件回调函数执行后,事件对象的所有属性都会被清除并回收以供重用,减少垃圾收集和内存使用的压力。

// 事件对象重用和回收的核心逻辑
SyntheticEvent.prototype.destructor = function() {
  this.target = null;
  this.currentTarget = null;
  this.dispatchConfig = null;
  this._targetInst = null;
  this.nativeEvent = null;
  this.isDefaultPrevented = false;
  this.isPropagationStopped = false;
  // 清除所有属性....
};

// Event pool
var eventPool = [];

// 从池中检索事件对象的函数
SyntheticEvent.getPooled = function(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
  if (eventPool.length) {
    var instance = eventPool.pop();
    SyntheticEvent.call(instance, dispatchConfig, targetInst, nativeEvent, nativeEventTarget);
    return instance;
  }
  return new SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget);
};

// 将事件对象返回到池的函数
SyntheticEvent.release = function(event) {
  event.destructor();
  eventPool.push(event);
};

而 JavaScript 事件每次触发时都会创建一个新的事件对象,这可能会增加内存使用量和垃圾收集的频率,特别是当事件频繁触发时(例如:滚动 或 输入)。”

4.使用模式

React 通过 JSX语法 允许我们直接在组件的元素上声明事件处理函数(合成事件)。

React 会自动处理添加和删除事件监听器,确保组件安装时添加监听器,卸载时删除监听器,从而避免内存泄漏。

export default function Button() {
  function handleClick() {
    console.log('click!');
  }

  return <button onClick={handleClick}>点我</button>;
}

Javascript 事件需要手动调用 addEventListener 添加事件监听器,同样手动调用removeEventListener 删除事件监听器:

document.addEventListener('DOMContentLoaded', function() {
  const button = document.querySelector('button');

  button.addEventListener('click', function() {
    console.log('click');
  });
});

5.总结

所以,React 的合成事件是 React 提供了一种高度抽象和集成的事件处理方式,并且可以更好地处理浏览器兼容性以及优化(卸载事件)等问题。它最终依然会被解析成原生事件。

而 JavaScript 原生事件就是浏览器所提供的标准 API,使用时需要更多的处理兼容性以及性能等边缘逻辑。

责任编辑:华轩 来源: 程序员Sunday
相关推荐

2020-08-02 23:20:36

JavaScriptmap()forEach()

2022-08-02 08:23:37

SessionCookies

2021-05-16 14:26:08

RPAIPACIO

2024-03-05 18:59:59

前端开发localhost

2021-12-17 14:40:02

while(1)for(;;)语言

2022-02-27 15:33:22

安全CASBSASE

2023-12-25 15:40:55

React开发

2020-03-09 20:56:19

LoRaLoRaWAN无线技术

2022-06-06 14:53:02

LoRaLoRaWAN

2022-09-07 18:32:57

并发编程线程

2022-09-08 18:38:26

LinuxWindowsmacOS

2020-11-09 14:07:53

PyQtQt编程

2021-07-01 07:51:45

React事件绑定

2023-12-15 09:21:17

ObjectJavaString

2022-08-31 08:33:54

Bash操作系统Linux

2022-08-22 07:06:32

MyBatisSQL占位符

2020-11-14 15:38:38

JavaScript代码技术

2020-03-23 11:28:56

PythonJavaScript技术

2018-07-20 14:00:51

LinuxmacOS内核

2012-10-18 14:46:01

Windows RTWindows 8
点赞
收藏

51CTO技术栈公众号