React 源码阅读(1)

1,790 阅读3分钟

关于读源码有无必要的讨论也有很多,我的想法是如果你不知道为什么需要读,那就没有必要。作为一个仅有三年编码经验的萌新,最近为了解决一个升级问题,学习新版本的使用,决定品一品这个香饽饽。此外,通过学习好的代码,也可以提升自己的编码高度。我希望记录下学习过程,以飨读者。

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文件夹里,我们先重点关注 reactreact-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,
};

下回分解~