2-3 React核心概念(一):组件&元素&实例
React 核心概念全景
在深入 React 源码之前,需要先搞清楚两个核心概念模块:
- Reconciliation(协调)——包含 Diff 算法和虚拟 DOM
- Rendering(渲染)——负责将虚拟 DOM 同步到真实 DOM
但在进入这两个核心模块之前,必须先理解 React 中最容易混淆的三个概念:组件(Component)、元素(Element)、实例(Instance)。
三者的定义与关系
React Element(React 元素)
React 元素是 React 世界中最基本的构建单元。当你写下 JSX 代码时,Babel 会将其转换为 React.createElement() 调用,最终生成一个普通的 JavaScript 对象。
// 你写的 JSX
const App = () => <div className="hello">App Component</div>;
// Babel 转换后的结果
const App = () => React.createElement('div', { className: 'hello' }, 'App Component');
jsx
这个 React.createElement() 返回的对象就是 React Element,它大致长这样:
{
$$typeof: Symbol(react.element),
key: null,
ref: null,
props: {
className: 'hello',
children: 'App Component'
},
type: 'div'
}
javascript
几个关键属性说明:
| 属性 | 说明 |
|---|---|
$$typeof | 类型标记,用于区分 React 元素和其他对象,也是一个安全特性(防止 XSS) |
type | 元素类型,可以是 HTML 标签字符串(如 'div')或函数/类(组件) |
key | 用于 Diff 算法中的元素标识 |
ref | 用于获取真实 DOM 节点的引用 |
props | 包含所有传入的属性和子元素(children) |
你可以在浏览器控制台中打印一个 React 组件来验证这个结构。
在 Babel Playground 中验证
访问 Babel 官网 的 "Try it out" 页面,在左侧输入 JSX,右侧会实时显示转换结果:
输入:
<div className="hello" id="world">
<img src="/static/image/bg.png" />
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
</div>
jsx
输出:
React.createElement('div', { className: 'hello', id: 'world' },
React.createElement('img', { src: '/static/image/bg.png' }),
React.createElement('ul', null,
React.createElement('li', null, 'item 1'),
React.createElement('li', null, 'item 2'),
React.createElement('li', null, 'item 3'),
)
);
javascript
可以看到 JSX 就是通过 React.createElement 嵌套调用来描述页面结构的——像套娃一样。JSX 的发明正是为了解决手写 createElement 过于繁琐、嵌套关系不直观的问题。
React Component(React 组件)
React 组件有两种定义方式:
函数式组件:
function App() {
return <div>App Component</div>;
}
jsx
类组件:
class App extends React.Component {
render() {
return <div>App Component</div>;
}
}
jsx
打印一个函数式组件,它的 type 属性是一个函数(而不是字符串),这说明 React Component 本质上也是一个 React Element,只是 type 不同:
{
$$typeof: Symbol(react.element),
type: function App() { ... }, // 函数引用
props: { ... }
}
javascript
两种组件的渲染机制:
| 组件类型 | 渲染方式 |
|---|---|
| 函数式组件 | 直接调用函数,获取返回的 Element |
| 类组件 | 创建实例(new),然后调用实例的 render() 方法 |
Component Instance(组件实例)
组件实例主要在类组件中存在。它的作用是:
- 追踪组件状态——通过
this.state存取组件状态 - 触发状态更新——通过
this.setState()更新状态 - 调用生命周期方法——
componentDidMount、shouldComponentUpdate等
函数式组件不需要实例化,直接调用函数即可。React 团队发明了 Hooks 来替代类组件中的生命周期方法,使得函数式组件也能拥有状态管理和副作用处理的能力。
三者关系总结
JSX 语法
↓ (Babel 转换)
React.createElement()
↓ (返回)
React Element (普通 JS 对象)
↓ (type 为函数时)
React Component (函数或类)
↓ (类组件实例化)
Component Instance (包含 state 和 lifecycle)
text
| 概念 | 本质 | 创建方式 |
|---|---|---|
| Element | 普通 JS 对象 | React.createElement() |
| Component | 函数或类 | 函数声明或 class extends React.Component |
| Instance | 类组件的实例化对象 | React 内部通过 new 创建 |
React 核心库的职责
通过理解这三者,可以看出 React 核心库承担了以下职责:
- 调用组件函数或创建类组件实例
- 管理组件的生命周期和状态
- 将 JSX 转换为 Element 对象树
- 协调新旧 Element 树的差异
- 将差异同步到真实 DOM
理解了组件、元素、实例这三个基础概念后,接下来就可以深入 React 的核心机制——协调(Reconciliation)和渲染(Rendering)了。
↑