用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 injectioninjection: {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

转载于:https://www.cnblogs.com/floor/p/10094323.html

react源码总览(翻译)相关推荐

  1. react源码解析之stack reconciler

    关于源码解读的系列文章,可以关注我的github的这个仓库, 现在才刚刚写,后续有空就写点.争取把react源码剖析透学习透.有不正确的地方希望大家帮忙指正.大家互相学习,共同进步. 本篇文章是官方文 ...

  2. react map循环生成的button_【第1945期】彻底搞懂React源码调度原理(Concurrent模式)...

    前言 估计会懵逼.今日早读文章由成都@苏溪云投稿分享. 正文从这开始~~ 最早之前,React还没有用fiber重写,那个时候对React调度模块就有好奇.而现在的调度模块对于之前没研究过它的我来说更 ...

  3. 全网最优雅的 React 源码调试方式

    什么?调试 React 源码还有优雅和不优雅之分? 别着急,我们先来听个故事: 东东是一名前端工程师,主要用 React 技术栈,用了多年之后想深入一下,所以最近开始看 React 源码. 他把 re ...

  4. build怎么调试 react_GitHub - bozhouyongqi/debug-react: 本地调试react源码环境

    [TOC] 工欲善其事,必先利其器. 在学习raect源码时,如果能够在浏览器中单步调试,势必会加深理解.其实可以借助webpack的resolve.alias将react等指向本地的目录,这样就不会 ...

  5. React源码分析与实现(一):组件的初始化与渲染

    原文链接地址:github.com/Nealyang 转载请注明出处 前言 战战兢兢写下开篇...也感谢小蘑菇大神以及网上各路大神的博客资料参考~ 阅读源码的方式有很多种,广度优先法.调用栈调试法等等 ...

  6. react源码分析-setState分析

    前言 是否有过这样的疑问: setState做了什么? setState是如何触发ui变化的? isWorking 如果此时isWorking为true,react将不会立即执行更新操作,而是把更新操 ...

  7. webuploader 怎么在react中_另辟蹊径搭建阅读React源码调试环境支持所有React版本细分文件断点调试...

    引言(为什么写这篇文章) 若要高效阅读和理解React源码,搭建调试环境是必不可少的一步.而常规方法:使用react.development.js和react-dom.development.js调试 ...

  8. 推荐一个 React 技术揭秘的项目,自顶向下的 React 源码分析

    大家好,我是你们的 猫哥,那个不喜欢吃鱼.又不喜欢喵 的超级猫 ~ just-react 这本书的宗旨是打造一本严谨.易懂的 React 源码分析教程. 为了达到这个目标,在行文上,本书会遵循: 不预 ...

  9. onclick 源码_仿照React源码流程打造90行代码的Hooks

    作者:苏畅 转发链接:https://mp.weixin.qq.com/s/YLSD4IojDWTPlov_RQtVAA 前言 你可能已经看过其它简易的Hooks实现.那么本文和其它实现有什么区别呢? ...

最新文章

  1. 点赞模块设计:Redis缓存 + 定时写入数据库实现高性能点赞功能
  2. 7 Papers Radios | 机器人「造孩子」;谷歌裸眼3D全息视频聊天技术公开
  3. 阶乘的累加(3.11)(Java)
  4. python递归合并排序_python 归并排序的递归法与迭代法(利用队列)实现,以及性能测试...
  5. Spring.net抛砖引玉系列(二)用接口来实现HelloWorld
  6. JVM 内存模型:运行时常量池
  7. FreeSWITCH第三方库(视频)的简单介绍(二)
  8. sqlserver可视化工具_数据分析之基础分析工具篇(修订版)
  9. Oracle行迁移和行链接
  10. 跨湖跨仓场景下如何实现海量数据分钟级分析
  11. hnu 暑期实训之蛇形矩阵
  12. 老男孩python全栈s21day21作业(面向对象)
  13. 安装配置MySQL5.7详细教程
  14. VMware下载,安装及创建虚拟机
  15. pta:人民币与美元汇率兑换程序(python)
  16. 没有明星代言,如何让用户相信你的产品?
  17. AOPlog4j2propagation的7种事务配置
  18. 汽车功能安全标准ISO 26262导入实践(下)
  19. mac安装配置maven
  20. Ubuntu 设置默认播放器、浏览器、图片查看器

热门文章

  1. C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)
  2. centos下搭建yum服务器
  3. linux自学(一)之vmware虚拟机安装
  4. 深入学习Redis(3):主从复制
  5. C#如何打开一个窗体,同时关闭该窗体
  6. 获取当前应用程序的文件名
  7. Requirejs2.0笔记
  8. Ext.Net学习笔记18:Ext.Net 可编辑的GridPanel
  9. 胸闷的原因有哪些? 相关解决偏方
  10. java怎么让进程停止_JAVA:如何在进程停止时调用一个方法(甚至有可能吗?)