关于读源码有无必要的讨论也有很多,我的想法是如果你不知道为什么需要读,那就没有必要。作为一个仅有三年编码经验的萌新,最近为了解决一个升级问题,学习新版本的使用,决定品一品这个香饽饽。此外,通过学习好的代码,也可以提升自己的编码高度。我希望记录下学习过程,以飨读者。
React 是什么?
这个问题乍看之下有点多余,但是想起即便是我在使用了React一段时间之后,我仍然对于React的认识处于一叶障目,不见泰山的阶段。对于这个问题的认识取决于个人的工作背景,有的人可能是从jQuery阶段一路升级到React,有的人可能是直接上手React(比如我),有的人可能是后端想了解一下前端的内容,这些不同的背景会有各自不同的认识。
官网的介绍是 一个创造用户界面的JavaScript库( A JavaScript library for building user interfaces.)
一言以蔽之,在经典的MVC(Model-View-Controller)模式中,React扮演的是View层的角色,Controller则是Redux(当然也可以选择其他),Model就是Redux Store中存储的状态。
从哪儿开始看源码?
我们知道React的源码托管在GitHub上,也知道从package.json开始,一般package.json中的main就是代码库的主入口。
The main field is a module ID that is the primary entry point to your program.
但是我们在React的package.json中 似乎找不到main?答案在这儿
因为React仓库是一个monorepo,也就是说React库和它相关的一些库都放在一起,使用monorepo的好处有很多,更方便组织管理,也简化了一些依赖关系等等。
所以React的源码我们要移步到 react/packages文件夹里。
此外由于React仍然是一个不断在发展的库(此时的版本是 v16.12.0), 一些后续的更新可能会废弃掉原有的功能,也会增加新的功能,文件的组织结构也会发生变化,这些都要有心理准备。
在react/packages文件夹里,我们先重点关注 react 和 react-dom 这两,写过React的应该对文件头这两行引入都不陌生:
import React from 'react';
import ReactDOM from 'react-dom';
比较 react 和 react-dom 这两源码的大小会发现,react-dom 的代码量大约是react的二十多倍,这是因为React已经不仅仅用在Web端,还能用在服务器端SSR,移动端和桌面端,比如React Native常见的文件头引入就不是 react-dom 而是react-native.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
对于具有跨平台能力的React体系来说,分包可以将抽象逻辑与平台实现分开。 react包即是抽象逻辑,它包含了主干逻辑,例如组件实现、更新调度等。react-dom 顾名思义就是一种针对DOM的平台实现,主要用于在 Web 端进行渲染。这是依赖倒置原则的典型应用。
react/src/React.js
铺垫了这么久,我们终于找到了第一个要研究的对象 github.com/facebook/re… 一个小快捷键是在GitHub页面按字母T,可以打开文件搜索功能。
在这个文件我们可以看到React暴露出来的API是:
const React = {
Children: {
map,
forEach,
count,
toArray,
only,
},
createRef,
Component,
PureComponent,
createContext,
forwardRef,
Fragment: REACT_FRAGMENT_TYPE,
StrictMode: REACT_STRICT_MODE_TYPE,
unstable_AsyncMode: REACT_ASYNC_MODE_TYPE,
unstable_Profiler: REACT_PROFILER_TYPE,
createElement: __DEV__ ? createElementWithValidation : createElement,
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
isValidElement: isValidElement,
version: ReactVersion,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,
};
下回分解~