这是一道考察React核心概念的基础题,虽然简单但很容易说错。关键在于理解:Element是描述,Component是函数或类。
下面从本质、创建方式、用途等维度来拆解。
一、核心结论
Element是一个普通的JavaScript对象,描述了你想要在屏幕上看到什么;Component是一个函数或类,接收props并返回一个Element树。
一句话总结:
- Element = 虚拟DOM节点(JS对象)
- Component = 生成Element的模板(函数/类)
二、详细对比表
| 维度 | React Element | React Component |
|---|---|---|
| 本质 | 普通JS对象 | 函数或类 |
| 创建方式 | React.createElement() 或 JSX | 定义函数或继承React.Component |
| 类型 | 对象类型(typeof element === 'object') | 函数类型或类类型 |
| 内容 | type、props、key、ref等属性 | 渲染逻辑(render方法或函数体) |
| 是否可实例化 | 否,它是不可变对象 | 类组件会被实例化,函数组件不会 |
| 生命周期 | 无 | 类组件有,函数组件用Hooks模拟 |
| 用途 | 描述UI结构 | 封装可复用的UI逻辑 |
| 命名规范 | 小写(DOM元素)或大写(组件) | 大写字母开头 |
| 内存占用 | 极轻量 | 较重(尤其是类组件实例) |
三、代码示例
React Element 示例
// 写法1:JSX(编译后变成 createElement)
const element1 = <div className="container">Hello</div>;
// 写法2:直接调用 createElement
const element2 = React.createElement('div', { className: 'container' }, 'Hello');
// element 的本质是一个普通对象
console.log(element1);
// 输出大致如下:
{
type: 'div',
props: {
className: 'container',
children: 'Hello'
},
key: null,
ref: null,
$$typeof: Symbol(react.element)
}
React Component 示例
// 函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 类组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
// Component 是函数或类
console.log(typeof Welcome); // 'function'(类本质也是函数)
Element 和 Component 的关系
// Component 返回 Element
function MyComponent() {
return <div>I am Element</div>; // 返回的是 Element
}
// 使用 Component 生成 Element
const element = <MyComponent />; // 这是一个 Element,type 是 MyComponent 函数
// React 内部渲染流程:
// <MyComponent /> → React.createElement(MyComponent, null) → Element对象
// → React 根据 element.type 调用 MyComponent() → 得到子 Element
// → 递归直到得到原生 DOM 类型的 Element
四、深入理解
1. Element 的 type 是关键
Element对象的type属性决定了它是什么:
// type 是字符串 → 原生 DOM 元素
{ type: 'div', props: { className: 'box' } }
// type 是函数 → 函数组件
{ type: MyComponent, props: { name: 'React' } }
// type 是类 → 类组件
{ type: class MyComponent extends ... , props: {...} }
2. Component 的两种形式
// 函数组件:纯函数,无实例
function Button({ text }) {
return <button>{text}</button>;
}
// 类组件:有实例,有生命周期
class Button extends React.Component {
render() {
return <button>{this.props.text}</button>;
}
}
3. 渲染过程对比
原始代码: <App />
↓ React.createElement()
Element: { type: App, props: {} }
↓ React 识别 type 是组件
调用 App() 或 new App().render()
↓ 返回新的 Element
Element: { type: 'div', props: { children: 'Hello' } }
↓ React 识别 type 是字符串(DOM)
创建真实 DOM 节点
↓
页面更新
五、面试常见追问
追问1:为什么 Component 必须返回 Element?
答: React的渲染引擎期望接收一个Element树来描述UI。Component的本质是一个转换器:输入props,输出Element。这样才能形成递归渲染:Component → Element → 更小的Component → 原生Element → DOM。
追问2:Element 是不可变的吗?
答: 是的。一旦创建,Element的type、props、children都不能改变。如果UI需要更新,React会创建新的Element树,然后通过Diff算法找出差异并更新真实DOM。这也是虚拟DOM能工作的基础。
追问3:可以在代码中直接使用 Element 对象吗?
答: 可以,但不常见。React内部大量使用Element对象,但开发者通常通过JSX间接创建。理论上你可以手动创建:
const element = {
type: 'div',
props: { className: 'box', children: 'Hello' }
};
// 但 React 要求 $$typeof 等内部属性,不建议手动创建
追问4:函数组件返回的 Element 和直接写的 Element 有区别吗?
答: 最终没有区别。无论是直接写的<div />还是组件返回的<div />,最终都是同一种Element对象。区别在于中间过程:组件的Element需要被”展开”才能得到最终的DOM Element树。
追问5:React 17 之后有什么变化?
答: React 17 引入了新的JSX转换,不再需要显式导入React:
// React 17 之前
import React from 'react';
const element = <div />; // 编译成 React.createElement('div')
// React 17 之后
const element = <div />; // 编译成 _jsx('div'),不依赖React导入
但Element的本质没有变化,仍然是普通JS对象。
六、类比理解(面试加分点)
可以把 React 比作餐厅:
- Element = 菜单上的菜品描述(”宫保鸡丁:鸡肉、花生、辣椒”)
- 只是文字描述,不是真正的菜
- 不可变,如果你想换菜,需要重新写描述
- Component = 厨师(函数组件)或菜谱(类组件)
- 厨师根据订单(props)做菜(返回Element)
- 菜谱定义了做菜的步骤(render方法)
- 真实DOM = 端上桌的菜
- 是真正被用户看到和交互的东西
- 只能由Element通过渲染得到
七、面试参考答案(精简版)
“React Element 和 Component 的核心区别是:Element是一个描述UI的普通JS对象,包含
type、props、children等属性,类似于虚拟DOM节点;Component是一个函数或类,接收props并返回一个Element树。Element是不可变的,由React.createElement或JSX创建;Component是可复用的UI模板,可以是函数组件或类组件。在渲染过程中,React会递归地将Component展开成最终的Element树,再映射成真实DOM。简单记忆:Component是工厂,Element是产品。”
快速记忆口诀
Element是对象,描述长啥样
Component是函数,返回Element树
组件大写字母开,元素小写DOM来
工厂产品要分清,面试再也不犯晕



