react源码总览(翻译)
用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源码总览(翻译)的更多相关文章
- React躬行记(16)——React源码分析
React可大致分为三部分:Core.Reconciler和Renderer,在阅读源码之前,首先需要搭建测试环境,为了方便起见,本文直接采用了网友搭建好的环境,React版本是16.8.6,与最新版 ...
- React源码剖析系列 - 生命周期的管理艺术
目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理.本系列文章希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期(C ...
- React源码解析:ReactElement
ReactElement算是React源码中比较简单的部分了,直接看源码: var ReactElement = function(type, key, ref, self, source, owne ...
- react 源码之setState
今天看了react源码,仅以记录. 1:monorepo (react 的代码管理方式) 与multirepo 相对. monorepo是单代码仓库, 是把所有相关项目都集中在一个代码仓库中,每个mo ...
- React 源码剖析系列 - 不可思议的 react diff
简单点的重复利用已有的dom和其他REACT性能快的原理. key的作用和虚拟节点 目前,前端领域中 React 势头正盛,使用者众多却少有能够深入剖析内部实现机制和原理. 本系列文章希望通过剖析 ...
- React 源码剖析系列 - 生命周期的管理艺术
目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理. 本系列文章 希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期 ...
- 读react源码准备
git源码地址:https://github.com/facebook/react react 里面就是 react源码 react里面的react文件夹就是react源码,react源码非常的少,总 ...
- react源码之render
1.最近学习react源码,刚刚入门,看了render的原理,到了fiberRoot的创建 如图:
- React源码之组件的实现与首次渲染
react: v15.0.0 本文讲 组件如何编译 以及 ReactDOM.render 的渲染过程. babel 的编译 babel 将 React JSX 编译成 JavaScript. 在 ba ...
随机推荐
- Java c# 跨语言Json反序列化首字母大小写问题
C#标准是首字母大写,Java规范是首字母小写,在序列化成Json之后,反序列化会出现反序列化失败的问题.. 从C#反序列化成JavaBean的时候通过如下注解可以直接解决该问题 @JsonNamin ...
- JS跨域:1.解决方案之-SpringMVC拦截器
一 拦截器代码 package com.wiimedia.controller; import java.util.List; import javax.servlet.http.HttpServle ...
- JavaScript中对数组和数组API的认识
JavaScript中对数组和数组API的认识 一.数组概念: 数组是JavaScript中的一类特殊的对象,用一对中括号“[]”表示,用来在单个的变量中存储多个值.在数组中,每个值都有一个对应的不重 ...
- CSS(选择器)
CSS(选择器) 作用:用于匹配 HTML 元素 选择器分类: 1.元素选择器 a{} 2.伪元素选择器 ::before{} (真实存在的元素) 3.类选择器 .link{} 4.属性选择 ...
- 小程序从后台输出的代码为HTML实体字符如何解决?
最近在做一个小程序的考试系统,从后台调出的数据是这个样子的 那么我遇到这个问题的时候想到的微信小程序的富文本即(wxParse),使用过wxParse的都知道,富文本必须得具体到单个的数据上才能使用, ...
- 第二章:第一个Netty程序
第一步:设置开发环境 • 安装JDK,下载地址http://www.oracle.com/technetwork/java/javase/archive-139210.html • 下载netty ...
- linux内核中断之看门狗
一:内核中断 linux内核中的看门狗中断跟之前的裸板的中断差不多,在编写驱动之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误:在Device Drivers /Watchdog ...
- 【redis 基础学习】(六)Redis HyperLogLog
摘自:http://www.mayou18.com/detail/o6M0v9mi.html Redis HyperLogLog 结构讲解 Redis 在 2.8.9 版本添加了 HyperLogL ...
- (细节)My SQL中主键为0和主键自排约束的关系
开始不设置主键 表的设计如下: 如果id的位置有好几个0的话:设置主键并且自动排序时,0会从1开始递增: Insert 进去 id = 0的数据,数据会从实际的行数开始增加,和从0变化不一样: 现在主 ...
- javascript系列1--把字符串当代码来执行
转发请标明来源:http://www.cnblogs.com/johnhou/p/javascript.html 请尊重笔者的劳动成果 --John Hou 在javascript中有多种方法可以 ...