William's Blog

如何理解React框架中的element、component以及instance?

element

  React中的element是一个用来描述React组件(component)或DOM节点的类型属性的普通javascript对象。element对象是React实现虚拟DOM的关键之一。在React框架中,element只是一个对UI元素(组件或者DOM节点)进行抽象描述的对象,一旦被创建,不能被修改。每个element对象包含两个核心的属性:type: (string | function | ReactClass)props: (Object)
  type属性取值类型可以是字符串、函数和ReactClass(React组件对应的class,class语法是ES6引入)。当type属性值类型是字符串时,element对象描述的是一个真实的DOM节点。节点的名字是type属性值,节点的属性名和属性值分别对应于element对象props属性属性值的键名和键值。比如有一个element对象:

{
  "type": "h1",
  "props": {
    "children": "Hello World!"
  }
}

  它描述的真实DOM节点如下:

<h1>Hello World!</h1>

  DOM节点之间的层级嵌套关系可以用element对象props属性属性值的children属性来描述,children属性值可以是新的element对象或者包含多个新的element对象的数组,也可以是其他类型。
  当element对象的type属相值类型是函数或者ReactClass时,element描述的是一个React组件。我们使用jsx语法定义一个简单的React组件Avatar:

const Avatar = ({ imgUrl, name }) => (
  <div>
    <img
      src={imgUrl}
      alt={`${name}的头像`}
    />
    <span>{name}</span>
  </div>
)

  当创建一个头像链接是 ‘a’、用户名为 ‘b’ 的Avatar组件时,可以用如下的element对象对创建出来的Avatar组件进行描述:

{
  "type": Avatar,
  "props": {
    "imgUrl": "a",
    "name": "b",
    "children": "null"
  }
}

  React框架支持以下三种方式来创建element对象:

  1. React.createElement(type, [props], […children])。使用方法如下:

    const ele = React.createElement('h1', null, 'Hello World!')
  2. jsx语法。使用方法如下:

    const ele = (<h1>Hello World!</h1>)
  3. React.createFactory(type)。使用方法如下:

    const eleFactory = React.createFactory('h1')
    const ele = eleFactory(null, 'Hello World!')

component

  element对象是不可变的,对于新添加的DOM节点来说,必须要新建对应的element对象。如果需要开发者来跟踪UI状态并控制element对象的销毁与创建,那React框架存在的意义不大。React设计出了组件机制,组件机制可以方便开发者将结构复杂的UI拆分成多个独立UI组件单独开发。独立的UI组件组合起来就可以构建出具有复杂交互功能的UI。
  React组件实现的功能是对element树的封装,在不同的输入下,组件输出不同的element树,最终渲染成不同的DOM树,以实现UI交互功能。开发者创建React组件的方式一般有两种:

  1. 函数。示例如下:

    const MyComponent = (props) => (<h1 {...props}>Hello world!</h1>)
  2. ES6 class语法,继承React.Component。示例如下:
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
  }
  
  render = () => (<h1 {...this.props}>Hello world!</h1>)
}

  不管React组件以何种方式被创建,它们实现的功能本质上都是以组件的属性props作为输入,输出不同的element树。它们的不同之处在于:使用ES6的class语法创建的组件可以保存自己内部的状态(state)并根据自身状态更新返回的element树(setState),同时它可以根据需要实现React组件的生命周期函数;使用函数创建的React组件是无状态的,无法实现React组件的生命周期函数。使用函数创建组件的开销要小于使用ES6 class语法的开销,当React组件不需要保存自身状态时可以优先考虑使用函数创建React组件。
  上一小节讲到,组件也是用element对象来描述。在React框架中,描述组件的element对象可以和描述DOM节点的element对象通过props属性值中的children相互嵌套。这一特性使得React框架支持相互独立的UI组件之间、组件与DOM节点之间互相嵌套组合形成新的UI组件,提高了代码的可复用性和可扩展性。

instance

  instance是面向对象语言中的词目,在React中可以被理解为 “组件实例”,上述使用ES6 class语法创建MyComponent的示例中this指向的就是MyComponent的实例。 React只会对使用ES6 class语法创建的组件进行实例化,并且instance的创建完全对开发者隐藏,开发者只需关心组件自身的逻辑。

总结

  1. 在React框架中,DOM节点和组件都使用element对象来描述。
  2. 在React框架中,组件本质上是接受属性props作为输入,输出不同的element树。
  3. 在React框架中,不管是渲染组件还是DOM节点,创建的都是element对象,React依据自身渲染规则将element对象映射到真实的DOM节点。
  4. 在React框架中,instance表示组件实例,React只会对以ES6 class语法创建组件进行实例化,并且整个实例化过程完全对开发者隐藏,开发者只需关心组件自身的逻辑。

参考文献

  1. Dan Abramov: React Components, Elements, and Instances

William

本博客作者 William 现任职于北京贝壳找房,从事web前端开发相关工作。
您可以通过Email与他取得联系