We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
我们阅读的 react 源码版本为 16.0.0-rc.3 。
facebook 内部自建了一个模块系统叫做“Haste”。它和 CommonJS 类似,也使用 require(),但是有些不同点容易引起大家的困惑。在 Haste 里,所有文件名是全局唯一的。在 react 源码中,只要根据模块的名字来引入模块即可:
require()
var setInnerHTML = require('setInnerHTML');
Haste 最早是为 Facebook 这种大型 app 设计的。他使得在不同的文件夹间移动文件很容易,无需担心相对路径的变化。在编辑器中搜索文件时也变得更方便准确。
React 在编译时,首先会有个脚本将所有文件拷贝到一个目录下 lib,然后在 require() 路径中加入 ./。
./
react 源码中的外部依赖很少,一般如果在 src 目录下找不到一个文件,可以去 fbjs 的 npm 包中查找。 然而,在 react 的入口文件 ReactEntry.js 中就看到了一个外部依赖包 object-assign。而且,react 自己写了个 babel-plugin , 在 scripts/babel/transform-object-assign-require 目录,将 Object.assign 转换为 require('object-assign')。
ReactEntry.js
object-assign
scripts/babel/transform-object-assign-require
Object.assign
require('object-assign')
. ├── build // 编译打包后的代码 ├── docs // 文档和官网 ├── fixtures // 包括一些小的 react 测试 app ├── packages // react 的 npm 包的模板 ├── scripts // 开发构建相关的脚本 └── src // 源码目录
src ├── ReactVersion.js // 一句代码,react 版本 ├── __mocks__ // ├── fb // 暂时用不到,不管 ├── isomorphic // React 核心 apis (如 React.Component React.Children) ├── node_modules // ├── package.json // ├── renderers // 将 react 树转换为不同平台的底层调用 ├── shared // isomorphic 和 renderers 共享的代码 └── test // 一些测试用到的代码
react 源码没有一个顶层目录专门用于测试代码,而是将单元测试的代码放在每个源码的附近。例如setInnerHTML.js 的测试代码在附近的 __tests__/setInnerHTML-test.js。
setInnerHTML.js
__tests__/setInnerHTML-test.js
react 源码里有很多 shared 目录。按照 react 源码的惯例(这个惯例不是强制的),一个文件一般只会 import 同级或下级目录的其他模块。但是有些不同目录下的模块需要共享,于是 react 源码将这些不同目录下的文件需要共享的代码放在 shared 目录。其规则是寻找最近的共同父目录,将共享代码存在 shared 文件夹。例如,src/renderers/dom/stack/client 和 src/renderers/dom/stack/server 共享的代码在 src/renderers/dom/shared。
src/renderers/dom/stack/client
src/renderers/dom/stack/server
src/renderers/dom/shared
这块的代码被称为 react 核心。它包含了所有的 React 顶级 API。例如:
React.createElement() React.Component React.Children
react 核心只包含了定义组件(components)所必需的 APIs。 它不包含协调器相关的代码,以及任何平台相关的代码。它同时被 React DOM 和 React Native 的组件所使用。这里面的代码编译后即为 react 的 npm 包。在编译后的浏览器 react 版本中,它暴露出一个全局变量 React。
src/renderers ├── __tests__ ├── art ├── testing ├── native ├── noop ├── shared | ├── stack | | └── reconciler // 协调器 | └── shared | └── event // 事件处理 └── dom // WEB 平台,暂时先关注这个目录即可 ├── ReactDOMNodeStreamRenderer.js ├── ReactDOMServerBrowserEntry.js ├── ReactDOMServerNodeEntry.js ├── ReactDOMServerStackEntry.js ├── ReactDOMStackEntry.js ├── ReactDOMStringRenderer.js ├── __tests__ ├── fiber // 核心算法重构,先不管 ├── shared ├── stack | ├── client | └── server └── test
react 需要支持不同的平台,如 React DOM 和 React Native。这些支持不同平台的代码在 renderers 中。Renderers 将 React 树转换为不同平台的底层调用。
我们主要阅读 web 平台相关的代码,关注 dom 目录。dom 目录下是 React DOM Renderer。它将 react 组件渲染为 DOM。这里实现了 ReactDOM 的顶层 APIs:
render() unmountComponentAtNode() findDOMNode()
React DOM 的代码编译为 ReactDOM npm 包。在浏览器编译版本中,暴露了全局变量 ReactDOM。
ReactDOM
不同的渲染平台如 React DOM 和 React Native,它们之间的很多逻辑是可以共用的。像声明式渲染,自定义组件,state,生命周期方法这些都应该是共用的。在不同平台上,它们的行为应该是一致的。
为了解决这个问题,不同平台间这些部分的代码是共用的。这部分代码被称为“协调器”(reconciler)。当 一次更新例如 setState() 开始执行,协调器调用组件树中组件的 render() 方法,然后执行 mounts、 updates 或 unmounts 组件。
setState()
render()
协调器并没有被独立打包因为目前它没有公共的 API 。相反,它们仅仅被渲染器如 React DOM 和 React Native 调用。
目前生产用的 React 版本,都是用的 Stack Reconciler。它位于 src/renderers/shared/stack/reconciler,并且同时被 React DOM 和 React Native 使用。
栈协调器用面向对象的方式编码,并且为每个 react 组件维护了一份“内部实例”的独立树。用户定义的("composite") 和平台自有的("host") 组件都存在内部实例。用户不能直接访问内部实例,并且他们的树也不会被暴露。
平台自带的组件(Host Components),例如 <div> 或 <View>,运行平台相关的代码。例如: React DOM 委托 stack reconciler 用 ReactDOMComponent 来处理 DOM 组件的 mounting, updates, 和 unmounting。
<div>
<View>
无论在哪个平台, <div> 和 <View> 以类似的方式处理多个字节点。 为了方便,stack reconciler 提供了一个 helper 叫做 ReactMultiChild。DOM 和 Native renderers 都用到这个 helper.
用户自定义的组件(Composite Components)在不同平台渲染器下的行为应该是一致的。这也是 Stack Reconciler 在 ReactCompositeComponent 中提供了一个共享的实现的原因。无论是什么渲染器,它应该是保持一致的。
未完待续。。。
The text was updated successfully, but these errors were encountered:
收藏
Sorry, something went wrong.
m
No branches or pull requests
react 源码阅读1-总览
我们阅读的 react 源码版本为 16.0.0-rc.3 。
facebook 自定义的模块系统
facebook 内部自建了一个模块系统叫做“Haste”。它和 CommonJS 类似,也使用
require()
,但是有些不同点容易引起大家的困惑。在 Haste 里,所有文件名是全局唯一的。在 react 源码中,只要根据模块的名字来引入模块即可:Haste 最早是为 Facebook 这种大型 app 设计的。他使得在不同的文件夹间移动文件很容易,无需担心相对路径的变化。在编辑器中搜索文件时也变得更方便准确。
React 在编译时,首先会有个脚本将所有文件拷贝到一个目录下 lib,然后在
require()
路径中加入./
。外部依赖
react 源码中的外部依赖很少,一般如果在 src 目录下找不到一个文件,可以去 fbjs 的 npm 包中查找。
然而,在 react 的入口文件
ReactEntry.js
中就看到了一个外部依赖包object-assign
。而且,react 自己写了个 babel-plugin , 在scripts/babel/transform-object-assign-require
目录,将Object.assign
转换为require('object-assign')
。目录结构
顶层目录(只保留部分阅读源码相关目录)
src 目录结构
单元测试
react 源码没有一个顶层目录专门用于测试代码,而是将单元测试的代码放在每个源码的附近。例如
setInnerHTML.js
的测试代码在附近的__tests__/setInnerHTML-test.js
。shared 目录下的代码
react 源码里有很多 shared 目录。按照 react 源码的惯例(这个惯例不是强制的),一个文件一般只会 import 同级或下级目录的其他模块。但是有些不同目录下的模块需要共享,于是 react 源码将这些不同目录下的文件需要共享的代码放在 shared 目录。其规则是寻找最近的共同父目录,将共享代码存在 shared 文件夹。例如,
src/renderers/dom/stack/client
和src/renderers/dom/stack/server
共享的代码在src/renderers/dom/shared
。isomorphic 目录
这块的代码被称为 react 核心。它包含了所有的 React 顶级 API。例如:
react 核心只包含了定义组件(components)所必需的 APIs。 它不包含协调器相关的代码,以及任何平台相关的代码。它同时被 React DOM 和 React Native 的组件所使用。这里面的代码编译后即为 react 的 npm 包。在编译后的浏览器 react 版本中,它暴露出一个全局变量 React。
renderers 目录
react 需要支持不同的平台,如 React DOM 和 React Native。这些支持不同平台的代码在 renderers 中。Renderers 将 React 树转换为不同平台的底层调用。
我们主要阅读 web 平台相关的代码,关注 dom 目录。dom 目录下是 React DOM Renderer。它将 react 组件渲染为 DOM。这里实现了 ReactDOM 的顶层 APIs:
React DOM 的代码编译为 ReactDOM npm 包。在浏览器编译版本中,暴露了全局变量
ReactDOM
。协调器 (Reconcilers)
不同的渲染平台如 React DOM 和 React Native,它们之间的很多逻辑是可以共用的。像声明式渲染,自定义组件,state,生命周期方法这些都应该是共用的。在不同平台上,它们的行为应该是一致的。
为了解决这个问题,不同平台间这些部分的代码是共用的。这部分代码被称为“协调器”(reconciler)。当 一次更新例如
setState()
开始执行,协调器调用组件树中组件的render()
方法,然后执行 mounts、 updates 或 unmounts 组件。协调器并没有被独立打包因为目前它没有公共的 API 。相反,它们仅仅被渲染器如 React DOM 和 React Native 调用。
栈协调器 (Stack Reconciler)
目前生产用的 React 版本,都是用的 Stack Reconciler。它位于 src/renderers/shared/stack/reconciler,并且同时被 React DOM 和 React Native 使用。
栈协调器用面向对象的方式编码,并且为每个 react 组件维护了一份“内部实例”的独立树。用户定义的("composite") 和平台自有的("host") 组件都存在内部实例。用户不能直接访问内部实例,并且他们的树也不会被暴露。
宿主组件(Host Components)
平台自带的组件(Host Components),例如
<div>
或<View>
,运行平台相关的代码。例如: React DOM 委托 stack reconciler 用 ReactDOMComponent 来处理 DOM 组件的 mounting, updates, 和 unmounting。无论在哪个平台,
<div>
和<View>
以类似的方式处理多个字节点。 为了方便,stack reconciler 提供了一个 helper 叫做 ReactMultiChild。DOM 和 Native renderers 都用到这个 helper.合成组件(Composite Components)
用户自定义的组件(Composite Components)在不同平台渲染器下的行为应该是一致的。这也是 Stack Reconciler 在 ReactCompositeComponent 中提供了一个共享的实现的原因。无论是什么渲染器,它应该是保持一致的。
未完待续。。。
The text was updated successfully, but these errors were encountered: