用react也有段时间了, 是时候看看人家源码了. 看源码之前看到官方文档 有这么篇文章介绍其代码结构了, 为了看源码能顺利些, 遂决定将其翻译来看看, 小弟英语也是半瓢水, 好多单词得查词典, 不当之处请批评. 直接从字面翻译的, 后面看源码后可能会在再修改下.


下面是翻译

这部分将给你介绍下react代码的基本结构, 代码约定和它的基本实现.

如果你想为react贡献代码的话, 我们希望这篇指南能让你写代码更加舒服.

我们不推荐将这些约定用在react应用中, 因为这些约定大多是基于一些历史原因存在的, 随着时间推移可能会发生变化.

外部依赖

react 几乎没有外部依赖. 通常require()指向的是react自己代码库的一个文件. 但是也有一些例外.

由于react想要通过库共享一些诸如Relay的小工具, 所以存在fbjs repository , 而且我们让他们是同步的. 我们没有依赖任何node生态系统下的小模块, 因为我们希望facebook的工程师的能能再任何必要的时候修改他们. fbjs中的任何工具都不能被认为是公共api, 并且他们只是为Facebook的一些工程使用, 比如react.

一级目录

克隆了react的仓库后你会发现在里边有几个一级目录.

  • packages目录包括一些元数据(如package.json)和react库提供的所有包的源码(src的下面), 如果你想修改代码, src下面就是你要花时间最多的地方.

  • fixtures目录包括了为贡献者准备的一些小的react的测试应用

  • build是react打包输出的目录. 他不在代码库管理范畴, 但是当你第一次打包后就会生成.

文档是放在和react不同的另一个仓库管理的.

还有一些其他一级目录, 他们大多是工具层面的, 在你贡献代码时可能不会用到他们能.

共同测试(Colocated Tests)

我们没有搞个一级目录来做单元测试. 我们把它放在了被测试文件相邻的被称为__tests__的目录.

举个例子, 对于setInnerHTML.js这个文件的测试被放在与他同级的__tests__/setInnerHTML-test.js这个里边.

这个词不知道怎么翻译

Warnings and Invariants

react中使用warning模块显示警告信息.

var warning = require('warning');

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

当警告条件是false的时候会展示警告信息

可以这么理解, 条件应该指示正常的情况, 而不是异常的情况. 就是说第一个参数是true表示的是正常, false是异常.

最好避免使用console取代warnings.

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时, 这个方法会直接抛出异常.

“Invariant” 就是说这个条件为真, 你可以认为他就是做了个断言.

保持开发环境和生产环境一致是很重要的, 因此invariant在生产环境和开发环境都可以抛出异常. 生产环境下的错误消息被自动替换成错误码, 以防增加代码体积.

Development and Production

你可以使用__DEV__这个为全局变量指定仅仅在开发环境才执行的代码块.

他是在编译过程中工作的, 他是在commonjs编译的时候检查process.env.NODE_ENV !== 'production'这个值.

单独编译的时候, 他在未压缩版是true, 在压缩版直接被去掉了.

if (__DEV__) {
// 这里边的代码只会带开发环境执行
}

Flow

我们最近开始引入flow做静态类型检查, 在文件头的注释里标注了@flow的使用了类型检查.

我们接受在现有代码加入flow类型检查的pull request (不错哎, 可以试着提个pull request哦). Flow的签名类似下面这样.

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

时机成熟的时候, 新代码要用Flow 签名, 你可以在本地运行yarn flow用Flow检查你的代码.

动态植入

react在一些模块使用了动态植入. 但是这个东西不太好, 因为他让代码比较难理解了. 他存在的理由是react一开始只把支持dom作为目标的. 但是后来杀出了个React Native, 他是基于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, 他的仓库包含了多个独立的包, 因此他们的修改可以合在一起, 而且issues也可以放在一个地方.

React核心

react的核心是所有顶级api, 包括:

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

react核心只包括定义组件必要的api, 并不包括reconciliation算法和平台特定代码. React DOM和React Native都使用了他们.

react核心的相关代码在packages/react里边. npm使用时在react这个包里边, 浏览器版的是react.js, 他挂载一个被称为React的全局变量.

Renderers

react起初是为DOM创造的, 但是后台通过RN被用来支持原生环境了. 这里介绍加react内部的“renderers”的理念.

“renderers”管理了react树如何变成平台可调用的东西.

Renderers也在packages里边

  • React DOM Renderer 把react 组件渲染进 DOM. 他实现了顶级的ReactDOM APIs, 在react-dom这个npm包里被暴露出来. 浏览器版叫react-dom.js, 通过ReactDOM这个全局变量暴露出来.

  • React Native Renderer把react组件渲染到原生视图层里. 他被RN内部使用.

  • React Test Renderer 把react组件渲染成JSON树, 他被Jest的一个特性Snapshot Testing使用, 在react-test-renderer这个npm包里可用.

另一个官方唯一支持的渲染器是react-art, 他曾经是个独立的库, 现在被移进来了.

注意

技术上react-native-renderer是很薄的一层, 只是用来和RN的实现相互配合, 真正的平台相关代码是RN库里一些native view.

Reconcilers(协调器)

相当多的渲染器, 如Reat DOM, React Native 需要共享一套逻辑. 尤其reconciliation算法需要足够的相似, 以便让rendering, 自定义组件, 状态, 生命周期函数和refs能跨平台工作.

为了解决这个问题, 不同的渲染器共用一些代码. 我们把React 中的这个部分叫做"reconciler". 当一个更新比如setState要执行了,Reconcilers就去在组件上调用render(), 然后mounts, updates, 或者unmounts他们.

Reconcilers没有独立成包, 因为他现在还没有公共API. 相反, 他仅仅是在渲染器被使用, 比如React DOM , React Native.

Stack Reconciler

Stack Reconciler 是在react15之前实现使用的, 现在已经不用了, 但是下一部分的文档还会有详细的介绍.

Fiber Reconciler

"Fiber"是为了解决stack reconciler固有问题和修复长期存在的bug所做的努力, 他从react16开始成为默认的Reconciler.

他的主要目标是:

  • 在chunks里分离可中断的工作

  • 在过程中重建, 重用work或者改变他的优先级(瞎翻译的)的能力

  • 在父子组件前进或回退以只是react中的布局的能力

  • 在render方法里返回多个元素的能力

  • 更好的支持错误边际

你可在这里这里阅读更多关于Fiber架构的相关信息. 但是React16对他做了封装, 默认不支持异步特性了.

他的源码在packages/react-reconciler里边.

事件系统

react实现了一个对renders透明的事件系统, 这个系统被用于react dom 和react native. 源码在packages/events;

这里有个视频https://www.youtube.com/watch?v=dRo_egw7tBc

react源码总览(翻译)的更多相关文章

  1. React躬行记(16)——React源码分析

    React可大致分为三部分:Core.Reconciler和Renderer,在阅读源码之前,首先需要搭建测试环境,为了方便起见,本文直接采用了网友搭建好的环境,React版本是16.8.6,与最新版 ...

  2. React源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理.本系列文章希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期(C ...

  3. React源码解析:ReactElement

    ReactElement算是React源码中比较简单的部分了,直接看源码: var ReactElement = function(type, key, ref, self, source, owne ...

  4. react 源码之setState

    今天看了react源码,仅以记录. 1:monorepo (react 的代码管理方式) 与multirepo 相对. monorepo是单代码仓库, 是把所有相关项目都集中在一个代码仓库中,每个mo ...

  5. React 源码剖析系列 - 不可思议的 react diff

      简单点的重复利用已有的dom和其他REACT性能快的原理. key的作用和虚拟节点 目前,前端领域中 React 势头正盛,使用者众多却少有能够深入剖析内部实现机制和原理. 本系列文章希望通过剖析 ...

  6. React 源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理. 本系列文章 希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期 ...

  7. 读react源码准备

    git源码地址:https://github.com/facebook/react react 里面就是 react源码 react里面的react文件夹就是react源码,react源码非常的少,总 ...

  8. react源码之render

    1.最近学习react源码,刚刚入门,看了render的原理,到了fiberRoot的创建 如图:

  9. React源码之组件的实现与首次渲染

    react: v15.0.0 本文讲 组件如何编译 以及 ReactDOM.render 的渲染过程. babel 的编译 babel 将 React JSX 编译成 JavaScript. 在 ba ...

随机推荐

  1. Java c# 跨语言Json反序列化首字母大小写问题

    C#标准是首字母大写,Java规范是首字母小写,在序列化成Json之后,反序列化会出现反序列化失败的问题.. 从C#反序列化成JavaBean的时候通过如下注解可以直接解决该问题 @JsonNamin ...

  2. JS跨域:1.解决方案之-SpringMVC拦截器

    一 拦截器代码 package com.wiimedia.controller; import java.util.List; import javax.servlet.http.HttpServle ...

  3. JavaScript中对数组和数组API的认识

    JavaScript中对数组和数组API的认识 一.数组概念: 数组是JavaScript中的一类特殊的对象,用一对中括号“[]”表示,用来在单个的变量中存储多个值.在数组中,每个值都有一个对应的不重 ...

  4. CSS(选择器)

    CSS(选择器) 作用:用于匹配 HTML 元素 选择器分类: 1.元素选择器  a{} 2.伪元素选择器  ::before{}  (真实存在的元素) 3.类选择器   .link{} 4.属性选择 ...

  5. 小程序从后台输出的代码为HTML实体字符如何解决?

    最近在做一个小程序的考试系统,从后台调出的数据是这个样子的 那么我遇到这个问题的时候想到的微信小程序的富文本即(wxParse),使用过wxParse的都知道,富文本必须得具体到单个的数据上才能使用, ...

  6. 第二章:第一个Netty程序

    第一步:设置开发环境 • 安装JDK,下载地址http://www.oracle.com/technetwork/java/javase/archive-139210.html   • 下载netty ...

  7. linux内核中断之看门狗

    一:内核中断 linux内核中的看门狗中断跟之前的裸板的中断差不多,在编写驱动之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误:在Device Drivers /Watchdog ...

  8. 【redis 基础学习】(六)Redis HyperLogLog

    摘自:http://www.mayou18.com/detail/o6M0v9mi.html Redis  HyperLogLog 结构讲解 Redis 在 2.8.9 版本添加了 HyperLogL ...

  9. (细节)My SQL中主键为0和主键自排约束的关系

    开始不设置主键 表的设计如下: 如果id的位置有好几个0的话:设置主键并且自动排序时,0会从1开始递增: Insert 进去 id = 0的数据,数据会从实际的行数开始增加,和从0变化不一样: 现在主 ...

  10. javascript系列1--把字符串当代码来执行

    转发请标明来源:http://www.cnblogs.com/johnhou/p/javascript.html  请尊重笔者的劳动成果  --John Hou 在javascript中有多种方法可以 ...