摘要:每次都信誓旦旦的给自己立下要好好学习源码的,结果都是因为某个地方卡住了,或是其他原因没看多少就放弃了。这次又给自己立个坚持看完源码。我看的源码版本是。本篇文章是官方文档里边的一篇文章的翻译,原文地址。
每次都信誓旦旦的给自己立下要好好学习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 Invariantsreact中使用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的全局变量.
Renderersreact起初是为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 ReconcilerStack 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
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/99854.html
摘要:写在前面的模板非常多,上有着各种各样的免费及付费模板。概述是一个基于设计的自适应多用途的管理后台模板。下一篇之模板的学习之路源码分析之部分 写在前面 bootstrap 的模板非常多,Envato 上有着各种各样的免费及付费模板。Metronic 是我最喜欢的模板之一(看一眼就喜欢上的那种),当前售价 $28 ,觉得赞的,不妨支持一下作者。觉得贵的,想必不用我说,你也会找到途径。:b ...
摘要:期间我也参考了上的一些项目,有的代码虽然简单,但是并没有开发讲解,对新手来说确实不友好。所以我想趁着这个机会,在写代码做项目的时候做一套开发教程讲解,让新手也能顺利上路。后端是选用项目有后台管理系统线上业务系统,全方位支持企业业务流程。 一 前言 关于这一系列文章的由来,我要做一个详细的说明,这些都在正文里面。关于代码的托管地址,请戳这里:GitHub关于开源代码的使用:免费用于个人、...
摘要:期间我也参考了上的一些项目,有的代码虽然简单,但是并没有开发讲解,对新手来说确实不友好。所以我想趁着这个机会,在写代码做项目的时候做一套开发教程讲解,让新手也能顺利上路。后端是选用项目有后台管理系统线上业务系统,全方位支持企业业务流程。 一 前言 关于这一系列文章的由来,我要做一个详细的说明,这些都在正文里面。关于代码的托管地址,请戳这里:GitHub关于开源代码的使用:免费用于个人、...
摘要:期间我也参考了上的一些项目,有的代码虽然简单,但是并没有开发讲解,对新手来说确实不友好。所以我想趁着这个机会,在写代码做项目的时候做一套开发教程讲解,让新手也能顺利上路。后端是选用项目有后台管理系统线上业务系统,全方位支持企业业务流程。 一 前言 关于这一系列文章的由来,我要做一个详细的说明,这些都在正文里面。关于代码的托管地址,请戳这里:GitHub关于开源代码的使用:免费用于个人、...
阅读 3179·2021-10-13 09:40
阅读 3596·2019-08-30 15:54
阅读 1288·2019-08-30 13:20
阅读 2951·2019-08-30 11:26
阅读 434·2019-08-29 11:33
阅读 1075·2019-08-26 14:00
阅读 2305·2019-08-26 13:58
阅读 3318·2019-08-26 10:39