0

0

React 内部机制探秘

一个新手

一个新手

发布时间:2017-10-25 15:06:31

|

2101人浏览过

|

来源于php中文网

原创

React 内部机制探秘 - React Component 和 Element

这篇文章比较偏基础,但是对入门 react 内部机制和实现原理却至关重要。算是为以后深入解读的一个入门,如果您已经非常清楚:

React Component Render => JSX => React.createElement => Virtual Dom

的流程,可以直接略过此文。

谷歌工程师一个风骚的问题

在几个月前,谷歌的前端开发专家 Tyler McGinnis 在其个人 twitter 账号上发布了 这样一条推文,引发了对 React 组件的讨论。

React 内部机制探秘

他抛出来的问题是 :如上述代码,React 组件 Icon 直接出现在代码中,到底算什么?

提供的选项有:

  • A. Component Declaration 组件声明

  • B. Component Invocation 组件调用

  • C. Component Instantiation 组件实例化

  • D. Using a Component 单纯地使用组件

有趣的是,参与回答的开发者中:

  • 有 15% 选择了 A 项;

  • 有 8% 选择了 B 项;

  • 有 45% 选择了 C 项;

  • 有 32% 选择了 D 项;

对 React 开发经验丰富的前端工程师来说,这个问题其实很好理解。它的关键在于:真正明白 React Element 和 React Components,以及 JSX 抽象层是如连通 React 的。当然也需要明白一些浅显的 React 内部工作机制。

这篇文章,就带领大家研究一下这个 JSX 抽象层的奥秘和 React Reconciliation 过程。

React 和 React Element 到底是什么?

让我们回到最初,思考一下最原始的问题,React 到底是什么?

简而言之,

React is a library for building user interfaces.

React 是一个构建视图层的类库(框架...whatever...)。不管 React 本身如何复杂,不管其生态如何庞大,构建视图始终是他的核心。记住这个信息,我们即将进入今天的第一个概念 — React Element

简单地说,React Element 描述了“你想”在屏幕上看到的事物。

抽象地说,React Element 元素是一个描述了 Dom Node 的对象。

请注意我的用词 — “描述”,因为 React Element 并不是你在屏幕上看见的真实事物。相反地,他是一个描述真实事物的集合。存在的就是合理的,我们看来看看 React Element 存在的意义,以及为什么会有这样一个概念:

  • JavaScript 对象很轻量。用对象来作为 React Element,那么 React 可以轻松的创建或销毁这些元素,而不必去太担心操作成本;

  • React 具有分析这些对象的能力,进一步,也具有分析虚拟 Dom 的能力。当改变出现时,(相比于真实 Dom)更新虚拟 Dom 的性能优势非常明显。

为了创建我们描述 Dom Node 的对象(或者 React Element),我们可以使用 React.createElement 方法:

const element = React.createElement( 
  'p', 
  {id: 'login-btn'}, 
  'Login'
)

这里 React.createElement 方法接受三个参数:

  • 一个表述标签名称的字符串 (p, span, etc.);

  • 当前 React Element 需要具有的属性;

  • 当前 React Element 要表达的内容,或者一个子元素。

上面 React.createElement 方法调用之后,会返回一个 javascript 对象:

{ 
  type: 'p', 
  props: { 
    children: 'Login', 
    id: 'login-btn' 
  } 
}

接着当我们使用 ReactDOM.render 方法,这才渲染到真实 DOM 之上时,就会得到:

Login

而这个才是真实的 Dom 节点。

到目前为止,并没有什么很难理解的概念。

React Element 深入和 React Component

这篇文章我们开篇就介绍了 React Element,而并不是像官网或者学习资料上来就介绍 React Component,我相信你理解了 React Element,理解 React Component 就是自然而然的事情了。

在真正开发时,我们并不直接使用 React.createElement,这样做简直太无聊了,每个组件都这样写一定会疯掉的。这时候就出现了 React Component,即 React 组件。

A component is a function or a Class which optionally accepts input and returns a React element.

没错,组件就是一个函数或者一个 Class(当然 Class 也是 function),它根据输入参数,并最终返回一个 React Element,而不需要我们直接手写无聊的 React Element。

所以说,实际上我们使用了 React Component 来生成 React Element,这对于开发体验的提升无疑是巨大的。

这里剖出一个思考题:所有 React Component 都需要返回  React Element 吗?显然是不需要的,那么 return null; 的 React 组件有存在的意义吗,它能完成并实现哪些巧妙的设计和思想?(请关注作者,下篇文章将会专门进行分析、讲解)

从场景实例来看问题

接下来,请看这样一段代码:

function Button ({ onLogin }) { 
  return React.createElement( 
    'p', 
    {id: 'login-btn', onClick: onLogin}, 
    'Login' 
  )
}

我们定义了一个 Button 组件,它接收 onLogin 参数,并返回一个 React Element。注意 onLogin 参数是一个函数,并最终像 id:'login-btn' 一样成为了这个 React Element 的属性。

直到目前,我们见到了一个 React Element type 为 HTML 标签(“span”, “p”, etc)的情况。事实上,我们也可以传递另一个 React Element :

const element = React.createElement(
  User, 
  {name: 'Lucas'},
  null 
)

注意此时 React.createElement 第一个参数是另一个 React Element,这与 type 值为 HTML 标签的情况不尽相同,当 React 发现 type 值为一个 class 或者函数时,它就会先看这个 class 或函数会返回什么样的 Element,并为这个 Element 设置正确的属性。

React 会一直不断重复这个过程(有点类似递归),直到没有 “createElement 调用 type 值为 class 或者 function” 的情况。

Relax System with CRM V.5
Relax System with CRM V.5

Relax System 是一套基于业务流程管控机制设计的新一代电子商务系统,做为“8Y8U商务解决方案”的重要组成部分,系统的设计重心位于企业的内部管理机制的建立与完善中,是一套真正能“有效提升管理水平”的商务系统。最新版本的 Relax System,更集成了CRM( Customer Relationship M

下载

我们结合代码再来体会一下:

function Button ({ addFriend }) {
  return React.createElement(
    "button", 
    { onClick: addFriend }, 
    "Add Friend" 
  ) 
} 
function User({ name, addFriend }) { 
  return React.createElement(
    "p", 
    null,
    React.createElement( "p", null, name ),
    React.createElement(Button, { addFriend })
  ) 
}

上面有两个组件:Button 和 User,User 描述的 Dom 是一个 p 标签,这个 p 内,又存在一个 p 标签,这个 p 标签展示了用户的 name;还存在一个 Button。

现在我们来看 User 和 Button 中,React.createElement 返回情况:

function Button ({ addFriend }) { 
  return { 
    type: 'button', 
    props: { 
      onClick: addFriend, 
      children: 'Add Friend' 
    } 
  } 
} 
function User ({ name, addFriend }) { 
  return { 
    type: 'p', 
    props: { 
      children: [{ 
        type: 'p',
        props: { children: name } 
      }, 
      { 
       type: Button, 
       props: { addFriend } 
      }]
    }
  }
}

你会发现,上面的输出中,我们发现了四种 type 值:

  • "button";

  • "p";

  • "p";

  • Button

当 React 发现 type 是 Button 时,它会查询这个 Button 组件会返回什么样的 React Element,并赋予正确的 props。

直到最终,React 会得到完整的表述 Dom 树的对象。在我们的例子中,就是:

{
type: 'p',
props: {
children: [{
type: 'p',
props: { children: 'Tyler McGinnis' }
},
{
type: 'button',
props: {
onClick: addFriend,
children: 'Add Friend'
}
}]
}
}

React 处理这些逻辑的过程就叫做 reconciliation,那么“这个过程(reconciliation)在何时被触发呢?”

答案当然就是每次 setState 或 ReactDOM.render 调用时。以后的分析文章将会更加详细的说明。

好吧,再回到 Tyler McGinnis 那个风骚的问题上。

React 内部机制探秘

此时我们具备回答这个问题的一切知识了吗?稍等等,我要引出 JSX 这个老朋友了。

JSX 的角色

在 React Component 编写时,相信大家都在使用 JSX 来描述虚拟 Dom。当然,反过来说,React 其实也可以脱离 JSX 而存在。

文章开头部分,我提到 “不常被我们提起的 JSX 抽象层是如何联通 React 的?” 答案很简单,因为 JSX 总是被编译成为 React.createElement 而被调用。一般 Babel 为我们做了 JSX —> React.createElement 这件事情。

再看来先例:

function Button ({ addFriend }) {
  return React.createElement(
    "button",
    { onClick: addFriend },
    "Add Friend" 
   )
} 
function User({ name, addFriend }) { 
  return React.createElement(
    "p",
    null,
    React.createElement( "p", null, name),
    React.createElement(Button, { addFriend })
  )
}

对应我们总在写的 JSX 用法:

function Button ({ addFriend }) { 
  return ( 
     
  )
}
function User ({ name, addFriend }) {
  return ( 
    

{name}

就是一个编译产出的差别。

最终答案和文末彩蛋

那么,请你来回答“Icon 组件单独出现代表了什么?”

Icon 在 JSX 被编译之后,就有:

React.createElement(Icon, null)

你问我怎么知道这些编译结果的?

或者

你想知道你编写的 JSX 最终编译成了什么样子?

我写了一个小工具,进行对 JSX 的实时编译,放在 Github仓库中,它使用起来是这样子的:

平台一分为二,左边可以写 JSX,右边实时展现其编译结果:

React 内部机制探秘

以及:

React 内部机制探秘

这个工具最核心的代码其实就是使用 babel 进行编译:

let code = e.target.value;
try {
    this.setState({
        output: window.Babel.transform(code, {presets: ['es2015', 'react']})
        .code,
        err: ''
    })
}
catch(err) {
    this.setState({err: err.message})
}

感兴趣的读者可以去 GitHub 仓库参看源码。

总结

其实不管是 JSX 还是 React Element、React Component 这些概念,都是大家在开发中天天接触到的。有的开发者也许能上手做项目,但是并没有深入理解其中的概念,更无法真正掌握 React 核心思想。

这些内容其实比较基础,但同时又很关键,对于后续理解 React/Preact 源码至关重要。在这个基础上,我会更新更多更加深入的类 React 实现原理剖析,感兴趣的读者可以关注。

我的其他几篇关于React技术栈的文章:

  • 通过实例,学习编写 React 组件的“最佳实践”

  • 从 React 绑定 this,看 JS 语言发展和框架设计

  • 做出Uber移动网页版还不够 极致性能打造才见真章

  • 解析Twitter前端架构 学习复杂场景数据设计

  • React Conf 2017 干货总结1: React + ES next = ♥

  • React+Redux打造“NEWS EARLY”单页应用 一个项目理解最前沿技术栈真谛

  • 一个react+redux工程实例


热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

178

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

35

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

79

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

2

2026.01.28

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

4

2026.01.28

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

8

2026.01.28

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

24

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

122

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

72

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.2万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

React核心原理新老生命周期精讲
React核心原理新老生命周期精讲

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号