资讯专栏INFORMATION COLUMN

React系列 --- Jsx, 合成事件与Refs(二)

LiuZh / 1852人阅读

摘要:系列系列简单模拟语法一系列合成事件与二系列算法实现分析三系列从到再到四系列与部分源码解析五系列从使用了解的各种使用方案六的诞生他是的一种扩展语法。这个函数接受组件的实例或元素作为参数,以存储它们并使它们能被其他地方访问。

React系列

React系列 --- 简单模拟语法(一)
React系列 --- Jsx, 合成事件与Refs(二)
React系列 --- virtualdom diff算法实现分析(三)
React系列 --- 从Mixin到HOC再到HOOKS(四)
React系列 --- createElement, ReactElement与Component部分源码解析(五)
React系列 --- 从使用React了解Css的各种使用方案(六)

JSX的诞生

他是 JavaScrip 的一种扩展语法。 React 官方推荐使用这种语法来描述 UI 信息。JSX 可能会让你想起某种模板语言,但是它具有 JavaScrip 的全部能力

JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。

它是类型安全的,在编译过程中就能发现错误。

使用 JSX 编写模板更加简单快速。

编译

本质上来讲,JSX 只是为 React.createElement(component, props, ...children) 方法提供的语法糖

123456
"use strict";

React.createElement("div", {
  className: "num",
  index: 1
}, React.createElement("span", null, "123456"));

具体效果可以在此体验

这就是为什么尽管你看不到里面使用过React,但是如果你不引入模块的话JSX会报错.

JSX原理

从上面的编译代码来看,JSX最终包含的信息其实分别是: 元素标签, 元素属性, 子元素.如果用Javascript对象来表示的话:

{
  tag: "div",
  attrs: { className: "num", index: 1},
  children: [
    {
      tag: "span",
      arrts: null,
      children: null
    }
  ]
}

所以整个过程大概如下

至于为什么会有中间编译成JS对象那一步而不直接编译成Dom元素.

除了普通页面还可能渲染到canvas或者原生App(React Native了解一下)

后面的diff比较需要用到

事件处理

React的事件是基于SyntheticEvent的实例实现模拟跨浏览器原生事件一样的接口,包括stopPropagation()preventDefault(),期望事件的行为跨浏览器是相同的.甚至兼容直达IE8.每个SyntheicEvent对象都有如下属性:

boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
DOMEventTarget target
number timeStamp
string type
基础科普

在JavaScript中,事件的触发实质上是要经过三个阶段:事件捕获、目标对象本身的事件处理和事件冒泡.

stopPropagation(): 停止事件冒泡

preventDefault(): 阻止默认行为

return false: 实际上使用这个的时候会做三件事

event.preventDefault();

event.stopPropagation();

停止回调函数执行并立即返回。

React是怎么管理事件系统的?

出于性能原因.React会通过池方式复用SyntheicEvent对象,这意味着事件调用完成之后event.target上所有的属性都会失效.意思就是当我们尝试异步方式调用React事件,因为复用的原因,在事件回调执行完之后SyntheicEvent对象将不再存在,所以我们无法访问其属性.

function onClick(event) {
  console.log(event); // => nullified object.
  console.log(event.type); // => "click"
  const eventType = event.type; // => "click"

  setTimeout(function() {
    console.log(event.type); // => null
    console.log(eventType); // => "click"
  }, 0);

  // Won"t work. this.state.clickEvent will only contain null values.
  this.setState({clickEvent: event});

  // You can still export event properties.
  this.setState({eventType: event.type});
}

比较常见的例子就是setState方法.

解决方案

event.persist()

事件回调中调用event.persist()方法,这样会在池中删除合成事件,并且允许用户代码保留对事件的引用。

缓存属性

我们可以将事件属性存储在事件函数并且传递给异步回调函数而不是直接在异步回调里访问它们.


Debouncing a synthetic event handler(不知道怎么翻译)

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

合成事件注册

源码注释

/**
 * Summary of `ReactBrowserEventEmitter` event handling:
 *
 *  - Top-level delegation is used to trap most native browser events. This
 *    may only occur in the main thread and is the responsibility of
 *    ReactDOMEventListener, which is injected and can therefore support
 *    pluggable event sources. This is the only work that occurs in the main
 *    thread.
 *
 *  - We normalize and de-duplicate events to account for browser quirks. This
 *    may be done in the worker thread.
 *
 *  - Forward these native events (with the associated top-level type used to
 *    trap it) to `EventPluginHub`, which in turn will ask plugins if they want
 *    to extract any synthetic events.
 *
 *  - The `EventPluginHub` will then process each event by annotating them with
 *    "dispatches", a sequence of listeners and IDs that care about that event.
 *
 *  - The `EventPluginHub` then dispatches the events.
 *
 * Overview of React and the event system:
 *
 * +------------+    .
 * |    DOM     |    .
 * +------------+    .
 *       |           .
 *       v           .
 * +------------+    .
 * | ReactEvent |    .
 * |  Listener  |    .
 * +------------+    .                         +-----------+
 *       |           .               +--------+|SimpleEvent|
 *       |           .               |         |Plugin     |
 * +-----|------+    .               v         +-----------+
 * |     |      |    .    +--------------+                    +------------+
 * |     +-----------.--->|EventPluginHub|                    |    Event   |
 * |            |    .    |              |     +-----------+  | Propagators|
 * | ReactEvent |    .    |              |     |TapEvent   |  |------------|
 * |  Emitter   |    .    |              |<---+|Plugin     |  |other plugin|
 * |            |    .    |              |     +-----------+  |  utilities |
 * |     +-----------.--->|              |                    +------------+
 * |     |      |    .    +--------------+
 * +-----|------+    .                ^        +-----------+
 *       |           .                |        |Enter/Leave|
 *       +           .                +-------+|Plugin     |
 * +-------------+   .                         +-----------+
 * | application |   .
 * |-------------|   .
 * |             |   .
 * |             |   .
 * +-------------+   .
 *                   .
 *    React Core     .  General Purpose Event Plugin System
 */

DOM将事件传给ReactEventListener注册到document,然后分发到具体节点.EventPluginHub负责事件的存储,合成事件以及池方式的实现创建和销毁,后面是各种类型的合成事件模拟,交互通过ReactEventEmitter将原生的DOM事件转化成合成的事件,触发将对应操作推入队列批量执行.因为浏览器会为每个事件的每个listener创建一个事件对象,上面提到的池方式复用就是为了解决高额内存分配的问题.

合成事件

Clipboard Events

Composition Events

Keyboard Events

Focus Events

Form Events

Mouse Events

Pointer Events

Selection Events

Touch Events

UI Events

Wheel Events

Media Events

Image Events

Animation Events

Transition Events

Other Events

event

其中事件都会被自动传入一个event对象,是由React将浏览器原生的event对象封装一下对外提供统一的API和属性.

this

因为React里调用传入方法的时候并不是通过对象方法方式,而是直接通过函数调用,所以里面指向的this是null或者undefined.

一般传入的时候需要手动用bind或者箭头函数显性绑定this指向

Refs & DOM

这是一种用于访问render方法中创建的DOM节点或React元素的方式.一般用于

处理表单,媒体控制

触发强制动画

集成第三方DOM库

创建Refs
class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }
  render() {
    return 
} }
访问 Refs
const node = this.myRef.current;

如果用于一个普通HTMl元素时,React.createRef() 将接收底层 DOM 元素作为它的 current 属性以创建 ref

ref 属性被用于一个自定义类组件时,ref 对象将接收该组件已挂载的实例作为它的 current

你不能在函数式组件上使用 ref 属性,因为它们没有实例。

回调Refs

不同于传递 createRef() 创建的 ref 属性,你会传递一个函数。这个函数接受 React 组件的实例或 HTML DOM 元素作为参数,以存储它们并使它们能被其他地方访问。

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);

    this.textInput = null;

    this.setTextInputRef = element => {
      this.textInput = element;
    };

    this.focusTextInput = () => {
      // 直接使用原生 API 使 text 输入框获得焦点
      if (this.textInput) this.textInput.focus();
    };
  }

  componentDidMount() {
    // 渲染后文本框自动获得焦点
    this.focusTextInput();
  }

  render() {
    // 使用 `ref` 的回调将 text 输入框的 DOM 节点存储到 React
    // 实例上(比如 this.textInput)
    return (
      
); } }

如果是组件间传递回调形式的 refs如下:

function CustomTextInput(props) {
  return (
    
); } class Parent extends React.Component { render() { return ( this.inputElement = el} /> ); } }
无状态组件中使用

因为无状态组件是不会被实例化的,但是我们可以用过一个变量访问其中的组件或者dom元素组件的实例引用

function CustomTextInput(props) {
  let inputRef;
  return (
    
inputRef = node} />
); }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106480.html

相关文章

  • React

    摘要:基础创建虚拟参数元素名称,例如参数属性集合,例如,,,从参数开始,表示该元素的子元素,通常这些元素通过创建,文本文件可以直接插入嘻嘻哈哈这是渲染器,将元素渲染到页面中。 React简介 FeceBook开源的一套框架,专注于MVC的视图V模块。实质是对V视图的一种实现。 React框架的设计没有过分依赖于某个环境,它自建一套环境,就是virtual DOM(虚拟DOM)。 提供基础AP...

    hlcc 评论0 收藏0
  • react开发教程(七)React事件系统

    摘要:按钮中使用原生事件中提供了很好的合成事件系统,但有时候也需要用到原生事件。而使用合成事件系统时则不需要,因为内部以及处理了。事件类型键盘事件焦点事件表单事件鼠标事件选择事件触摸事件事件动画事件图像事件媒体事件剪贴板事件上一篇开发教程六与 事件系统 Virtual DOM在内存中是以对象的形式存在的,如果想要在这些对象上添加事件的话,React是基于Virtual DOM实现了一个合成事...

    walterrwu 评论0 收藏0
  • React系列 --- 简单模拟语法(一)

    摘要:系列系列简单模拟语法一系列合成事件与二系列算法实现分析三系列从到再到四系列与部分源码解析五系列从使用了解的各种使用方案六前言我们先不讲什么语法原理先根据效果强行模拟语法使用实现一个简易版的第一步我们先用类 React系列 React系列 --- 简单模拟语法(一)React系列 --- Jsx, 合成事件与Refs(二)React系列 --- virtualdom diff算法实现分析...

    piglei 评论0 收藏0
  • [React Native Android 安利系列]ReactNative中的reactjs基础

    摘要:个人感觉这与中的布局文件类似。其中的会被解析。中的标签,由基础库提供。认为,我们的程序是一个状态机。支持我们更改状态,从而引起视图的变化。绑定事件是放在中的。事件名称直接写为标签的属性,其值则是对应的事件处理函数。 这一系列课程说了很多关于react-native的知识,都是有关于样式,底层,环境等知识的,现在我们来学习一下reactjs的基础知识。我们的代码,我们创建的组件的相关知识...

    EddieChan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<