# React

虽然平时我们都喜欢说我们用React作为我们的核心框架,但其实大部分人都不知道React到底是个什么东东。事实上自从Facebook把ReactReactDOM分包发布之后,React就不仅仅是一开始的前端框架了,如果在15版本之后去看一下reactreact-dom的源码大小,你就会发现,react仅仅1000多行代码,而react-dom却将近2w行。是的你没看错,而且你很可能也没有想错,其实大部分的框架逻辑都在react-dom当中,那么react到底是个什么东东呢?

# ReactElement

能来看源码的同学,我相信你们至少肯定知道JSX代码在编译之后是什么样子的

// JSX
<div id="id">text</div>

// js
React.createElement('div', {id: 'id'}, 'text')

而这恰恰就是react这个包最最核心的代码,详细源码解析可以看这里

其实React的核心产出,就是element,这个element是平台无关的,只跟你传入的参数有关,比如上面的例子,你传入的是一个字符串div,那么你的element.type就是div,而字符串的类型,对于react-dom平台就意味着是HostComponent也就是原生html标签。我们可以看一下react里定义的type类型

export const IndeterminateComponent = 0; // 不确定是ClassComponent还是functionalComponent
export const FunctionalComponent = 1;  
export const ClassComponent = 2;
export const HostRoot = 3; // reactDom.render()接受的第二个参数
export const HostPortal = 4; // portal
export const HostComponent = 5;  // 原生html即诶点
export const HostText = 6;   // 文本节点
export const CallComponent_UNUSED = 7;
export const CallHandlerPhase_UNUSED = 8;
export const ReturnComponent_UNUSED = 9;
export const Fragment = 10;
export const Mode = 11;  // AsyncMode
export const ContextConsumer = 12;
export const ContextProvider = 13;
export const ForwardRef = 14;
export const Profiler = 15;
export const TimeoutComponent = 16;

当然在React.createElement的时候返回的内容里的type肯定不是这些值,而是后期react-dom会根据element的类型转换成Fiber的类型

这写类型在React Fiber里面叫做TypeOfWork,对于不同的类型,后期会有不同处理。而react在这里起的作用就是创建element并包含一些源信息,以便后期不同平台根据自己的特性进行处理。

# 内置类型

当然我们用react当然不仅仅用他的createElement,很多同学提到context api,确实,这也是react的API,但其实呢,他们也是为ReactElement服务的。

我们先来看看context api

const { Provider, Consumer } = React.createContext('defaultValue')

具体API源码解析看这里

在使用的的时候我们会把ProviderConsumer作为createElement的参数使用,所以这两个其实是一个特殊的类型,他们不是class也不是function和字符串,他们是一个特定的对象,来告诉后期平台他们是特殊的节点。

context.Provider = {
  $$typeof: REACT_PROVIDER_TYPE,
  _context: context,
};

还有即将在17版本中出现的AsyncMode,我们可以这么用:

const AsyncMode = React.unstable_AsyncMode


<AsyncMode></AsyncMode>

那么AsyncMode是什么呢?其实他是一个Symbol,也就是说是一个唯一标志位,告诉平台这个节点的子节点要用异步的模式进行渲染,这就是他的任务。

# Component

当然还有一个少不了用的就是React.Component了,我们声明的ClassComponent都是继承自这个基类的。不过其实他没什么内容,只是在原型上定义了setState, forceUpdate等方法,而它们最终调用的是个个平台提供给实例的updater对象上的方法,所以源码非常简单,就不多详细讲解了,源码位置packages/react/src/ReactBaseClass.js,相信js基础过关的同学都看得懂。

Component.prototype.setState = function(partialState, callback) {
  invariant(
    typeof partialState === 'object' ||
      typeof partialState === 'function' ||
      partialState == null,
    'setState(...): takes an object of state variables to update or a ' +
      'function which returns an object of state variables.',
  );
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

# 总结

总的来说react部分的源码是非常简单的,总共也就1000多行,还有很多是注释,大家看一遍也花不了多少时间,注意看的时候不要去考虑React是如何做渲染的,只看源码理解他的输入输出就行。