是 React 元素还是 React 组件?

来自 stackoverflow 提问 How to detect a React component vs. a React element? (opens new window)

React 组件我是知道的 class、function 声明的两种

React 元素听过,到底是什么啥玩意

# Reat 元素

先说下 JSX,Javascript 的扩展语法

React 开发通常在 .jsx 或 .tsx 结尾文件中写 JSX 代码的

它到底是什么?它就是下面这个玩意,需要 Babel 转码才能正常使用

// 这就是 JSX,请结合 Babel 测试
const ele = <div>我是 JSX</div>

console.log(typeof ele) // object
1
2
3
4

看着像 HTML 标签元素一样,其他它是一个对象

所以 JSX 是一个像 HTML 标签元素的对象

没错,这就是 React 元素 (opens new window)

React 元素本质是调用 React.createELement 方法返回的对象

记住,只要最终通过 React.createElement 方法返回的对象都是 React 元素

# 判断 React 元素

通过 React.isValidElement 判断

本质是判断 React 元素对象上的 $$typeof 属性

React 元素结构,直观感受下

 React 元素结构

# 创建 React 元素的几种方式

class Foo extends React.Component {
  render(){
      return <h1>Hello</h1>;
  }
}
function Bar() {
  return <p>323</p>
}

let ele = <h3>323</h3>
let foo = <Foo />
let bar = <Bar />

// 具体看 Babel 转换后的
class Foo extends React.Component {
  render() {
    return /*#__PURE__*/ React.createElement("h1", null, "Hello");
  }
}
function Bar() {
  return /*#__PURE__*/ React.createElement("p", null, "323");
}

// 下面都是 React 元素,通过调用 React.createElement 返回的对象
let ele = /*#__PURE__*/ React.createElement("h3", null, "323");
let foo = /*#__PURE__*/ React.createElement(Foo, null);
let bar = /*#__PURE__*/ React.createElement(Bar, null);


// 结果很明显的
React.isValidElement(ele) // true
React.isValidElement(foo) // true
React.isValidElement(bar) // true


// 其实下面的也是 React 元素
let bar1 = Bar()
React.isValidElement(bar1) // true

// 但下面的不是
let foo1 = new Foo() // foo1 不是 React 元素
React.isValidElement(foo1) // false

// 但通过 render 方法返回的就是
let foo2 = Foo.prototype.render()
React.isValidElement(foo2) // true
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
38
39
40
41
42
43
44
45
46

# React 元素分类

分为 DOM 类型与 class 或 function 创建的自定义合成类型

通过 React 元素对象 type 属性判断

字符串是 DOM 类型, function 为合成类型

通过上面 React 元素结构图很直观的看到

// DOM 类型 React 元素
function isDOMTypeElement(element) {
  return React.isValidElement(element) && typeof element.type === 'string'
}

// 自定义合成类型的 React 元素
function isCompositeTypeElement(element) {
  return React.isValidElement(element) && typeof element.type === 'function'
}
1
2
3
4
5
6
7
8
9

# React.isValidElement 判断原理

判断传入对象上的 $$typeof 是否是 Symbol(react.fragment) 符号

const REACT_ELEMENT_TYPE = Symbol.for('react.element')
function isValidElement(object) {
  return typeof object === "object" && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
1
2
3
4

# React 组件

React 只包含两种:class 类组件与 function 组件

class 类组件需要继承 React.Component 或 React.PureComponet 方法创建,否则报错

组件本质由 React 元素组成

# 判断 React 组件类型

只要判断各自的原型链上是否存在 isReactComponent,存在且为真,则 class 组件,否则是函数组件

// ture -> class 组件,false -> function 组件,但他们都是 react 组件
function isReactComponent(comp) {
  return typeof comp === 'function' && !!comp.prototype.isReactComponent
}
1
2
3
4

如果不考虑将 ES6 代码转换为 ES5 代码的话,通过 class 或 function 关键字判断

如果将 class 转换为 function 的话,此判断就失效了,毕竟 class 是 function 语法糖

// ture -> class 组件,false -> function 组件,但他们都是 react 组件
function isReactClassComponent(comp) {
  return isReactComponent(comp) && comp.toSring().startsWith('class')
}
1
2
3
4

class 组件分为 PureComponet 与 Component 两种,判断如下:

// ture -> PureComponet,false -> Component
function isReactClassComponent(comp) {
  return isReactComponent(comp) && comp.prototype.isPureReactComponent
}
1
2
3
4

# React 元素与组件的关联图

React 元素与组件的关联图

# 小结

React 元素组成 React 组件

React 元素通过 React.isValidElement 方法判断

本质是判断 React 原型的 $$typeof 字段

直接声明的 React 元素是 DOM 类型,由 class 或 function 创建的是合成类型

通过 React 元素的 type 判断

React 组件通过原型链上的 isReactComponent 判断

React 组件分为 class 与 function 类型

class 类型又分为 Component 类型与 PureComponent 类型

通过原型链上的 isPureReactComponent 判断

以上,提供了一个好用的检查工具包react-type-check (opens new window)

扫一扫,微信中打开

微信二维码