每次都信誓旦旦的给本身立下要好好进修react源码的flag,效果都是因为某个处所卡住了,或是其他缘由没看若干就摒弃了。此次又给本身立个flag-对峙看完react源码。为了催促本身,特开设如许一个专栏来纪录本身的进修进程,这意味着这个专栏的文章质量并不高,你能够拿来参考参考,切莫全信,我不想误人子弟,背面假如学有所成再斟酌产出些好点的文章。 假如发明文章中有什么不当之处,欢迎批评交换。我看的源码版本是
16.8.2
。
为了看react源码,我查找了不少材料,这里引荐两个参考材料,个人以为写得不错。
- 慕课网一个课的电子书,他有个源码剖析的视频教程,应当不错,不过我没买。
- 一个知乎专栏,写得很清楚,只不过是
15.6.2
的, 在react16
内里一些要领找不到了。
本篇文章是官方文档里边的一篇文章的翻译,原文地点。
这部份将给你引见下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
;