react代码库概述

原文: Codebase Overview
译文: react源码概述

本文主要是概述react代码的组织,约定和实现。

如果你想为react做出一份贡献,请阅读贡献指南,这将会使你更便捷的做出贡献。

不是我们一定要在react应用中推行这些约定,很大部分的原因是因为历史包袱,随着时间的改变,这些都会改变。

外部的依赖

React几乎没有任何的外部依赖。通常require都是引入的react内部的文件。当然,也有极个别的例外情况。

fbjs代码库是个意外,因为React与像Relay之类的库需要共享一些小的实用程序,我们会保持它的同步。我们不会依赖node生态系统中可用的类似的库,如果真的有需要,会对这些库进行更改之后使用。fbjs库中的一些工具类都不会作为公开的API去,仅仅是给像React这样的fb的项目去使用。

顶层的文件夹

在你clone了react代码库之后,就会看到一些顶层的文件夹:

  • packages
    这个包含了代码所有包的一些基础信息(比如: package.json)和源码(src目录)。如果你要修改代码,那么src下的代码将是你花费时间精力的地方。
  • fixtures
    这个是针对贡献的代码的一个测试程序。
  • build
    build是React的构建输出。它不在存储库中,但是在第一次构建它之后它将出现在你clone的React中。

还有一些其他顶层文件夹,但它们主要作为工具使用,你做的贡献可能并不需要这些。

测试

我们没有单元测试的顶级目录。相反,我们将它们放入一个名为tests的目录中,该目录就是相对于它们测试的文件。

Warnings 和 Invariants

React使用warning模块来展示警告信息。

var warning = require('warning');

warning(
  2 + 2 === 4,
  'Math is not working today.'
);

触发这个警告的条件是当条件为false时。

之所以这样是因为条件是应该反应成正常情况而不是针对特殊情况。

笔者认为: 不是为了警告而警告,语意以条件为主,而不是以警告为主。

对于在console里重复的发送垃圾信息,这或许是个好的想法:

var warning = require('warning');

var didWarnAboutMath = false;
if (!didWarnAboutMath) {
  warning(
    2 + 2 === 4,
    'Math is not working today.'
  );
  didWarnAboutMath = true;
}

警告仅仅在开发环境下可用。在生成环境中,就不再使用。如果你想根据条件禁止执行代码,请使用invariant:

var invariant = require('invariant');

invariant(
  2 + 2 === 4,
  'You shall not pass!'
);

同样的,当条件为false的时候,会触发。

保持开发和生产环境行为的一致性非常重要,因此在开发和生产中都可以使用这个。错误消息会自动替换为生产中的错误代码,以避免对字节大小产生影响。

Development and Production

你可以使用__DEV__来判断环境,进行针对开发环境的开发。

它在编译步骤中关联,并在CommonJS构建中变为process.env.NODE_ENV !== 'production'检查。

对于独立部署,在unminified build的时候是true, 在minified build的时候通过if块来去除。

if (__DEV__) {
  // This code will only run in development.
}

Flow

我们最近开始向代码库引入Flow检查。让标题注释中标有@flow注释的文件进行类型检查。

我们接受将flow注释添加到现有代码的PR。流注释看起来像这样:

ReactRef.detachRefs = function(
  instance: ReactInstance,
  element: ReactElement | string | number | null | false,
): void {
  // ...
}

尽可能的在新加的代码里添加Flow,然后可以运行yarn flow检查。

动态注入

React在一些模块中使用动态注入。虽然总是看起来很清晰,但它仍然是不够好,因为它阻碍了对代码的理解。因为以前在React中只考虑到DOM,。之后React Native fork了React的代码进行扩展。所以添加了动态注入让React Native 覆盖一些行为。

你可能会看到一些模块声明的动态注入,类似这样:

// Dynamically injected
var textComponentClass = null;

// Relies on dynamically injected value
function createInstanceForText(text) {
  return new textComponentClass(text);
}

var ReactHostComponent = {
  createInstanceForText,

  // Provides an opportunity for dynamic injection
  injection: {
    injectTextComponentClass: function(componentClass) {
      textComponentClass = componentClass;
    },
  },
};

module.exports = ReactHostComponent;

注射部分没有任何特殊处理。但按照惯例,这意味着该模块希望在运行时将一些(可能是平台特定的)依赖项注入其中。

代码库中有多个注入点。在未来,我们打算摆脱动态注入机制,并在构建过程中静态地连接所有碎片。

多个包

React是一个monorepo。它的存储库包含多个独立的包,以便它们的更改可以协调在一起,并在一个地方发布。

React核心

“核心”包括React的顶层API,例如:

  • React.createElement()
  • React.Component
  • React.Children

注意:React核心仅包含定义组件的API。 它不包括reconciler算法或任何特定于平台的代码。它由React DOM和React Native组件使用。

对上面核心理解有不明白的,可以查看这篇文章 -- Dan

React的核心代码在packages/react下面,作为react npm包。对外暴露全局的React。

Renderers

React最初是为DOM而构建的,但是后来又开始支持React Native。于是乎就像React内部引入了renderers的概念。

renderer负责React树如何被底层平台调用。

renderer同样存在packages/下面:

唯一正式支持的渲染器是react art。它曾经在一个单独的GitHub存储库中,但我们现在将它移动到主源代码树中。

从技术上讲,react-native-renderer是一个非常薄的层,使React与React Native实现进行交互。事实上,原生视图特定于平台的代码管理是和组件一起在React native 仓库中。

Reconcilers

即使是像React DOM和React Native这样极为不同的渲染器也需要分享很多逻辑。特别是reconciliation算法应该尽可能的相似,以便声明性呈现,自定义组件,状态,生命周期方法和ref在不同平台上一样的工作。

为了解决这个问题,不同的渲染器在它们之间共享一些代码。我们将React的这一部分称为“reconciler(协调者)”。当类似setState这样的更新时,reconciler在组件上调用render方法,并且mounts, updates或者 unmounts.

Reconcilers没有单独拆分成包,因为没有公共的API。相反,它们仅由React DOM和React Native等渲染器使用。

Stack Reconciler

stack(堆栈) reconciler是react 15版本及更早的实现。我们已经停止使用他了,但是我们会在下一节详细的介绍他。

Fiber Reconciler

“fiber” reconciler 是最近努力的成果,主要是解决‘stack reconciler’中的问题以及其他一直存在的问题。他在react16之前一直是默认的reconciler。
Fiber reconciler 主要的目标是:

  • 能够以块的形式分割可中断的工作
  • 能够在处理的时候确定优先级,重新定位和重用的工作。
  • 能够在父子任务之间从容切换(yield back and forth),以支持React的布局刷新
  • 能够从render返回多个元素
  • 更好地支持error boundary

你可以在此处此处阅读有关React Fiber 构建的更多信息。虽然它已随React 16一起提供,但默认情况下尚未启用异步功能。

他的源码在 packages/react-reconciler.

Event System

React实现了一个合成事件系统,它与渲染器无关,并且与React DOM和React Native一起工作。他的源码在 packages/events

这里有个关于深入事件系统的视频(66分钟)

What Next?

阅读下一章节关于pre-React 16 reconciler更详细的实现。我们目前还没有关于reconciler的内部的文档。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,431评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,637评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,555评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,900评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,629评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,976评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,976评论 3 448
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,139评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,686评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,411评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,641评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,129评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,820评论 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,233评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,567评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,362评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,604评论 2 380

推荐阅读更多精彩内容

  • Foreword: 首先那要说明下,以下是我看到的一篇文章,但是原文是英文的,我只是做一个搬运工把他搬过来~主要也...
    Howie126313阅读 10,861评论 4 41
  • 学习如何在Flow中使用React 将Flow类型添加到React组件后,Flow将静态地确保你按照组件被设计的方...
    vincent_z阅读 6,387评论 4 21
  • 参考文章:深度剖析:如何实现一个Virtual DOM 算法 作者:戴嘉华React中一个没人能解释清楚的问题——...
    waka阅读 5,981评论 0 21
  • 3. JSX JSX是对JavaScript语言的一个扩展语法, 用于生产React“元素”,建议在描述UI的时候...
    pixels阅读 2,872评论 0 24
  • 墨尔本是花园。墨尔本的孩子是花朵。 墨尔本是个处处很有爱的城市,每个人都能有自己安之若素的角色,就我所看到的,大家...
    OScarsab阅读 777评论 0 0