function Component(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.isReactComponent = {};
Component.prototype.setState = function (partialState, callback) {
!(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void 0;
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
Component.prototype.forceUpdate = function (callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
function createElement(type, config, children) {
var propName = void 0;
// Reserved names are extracted
var props = {};
var key = null;
var ref = null;
var self = null;
var source = null;
······
return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
}
这里又返回了一个ReactElement方法,再顺着往下找:
var ReactElement = function (type, key, ref, self, source, owner, props) {
var element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner
};
······
return element;
};
前言
react使用也有一段时间了,大家对这个框架褒奖有加,但是它究竟好在哪里呢? 让我们结合它的源码,探究一二!(当前源码为react16,读者要对react有一定的了解)
回到最初
根据react官网上的例子,快速构建react项目
打开项目并跑起来以后,暂不关心项目结构及语法糖,看到 我们console一下,看看有什么结果。
App.js
里,这是一个基本的react组件可以看到,
<App/>
组件其实是一个JS对象,并不是一个真实的dom。上面有我们很熟悉的
props
,ref
,key
,我们稍微修改一下console,看看有什么变化。可以看到,
props
,key
都发生了变化,值就是我们赋予的值,props
中嵌套了children属性。可是为什么我们嵌入的是div,实际上却是一个对象呢?打开源码
首先打开
index.js
可以知道目前用上的是
./cjs/react.development.js
,直接打开文件。 根据最初的代码,我们组件<App/>
用到了React.Component。找到React暴露的接口:接着找到
Component: Component
方法,上面就是一些简单的构造函数,也可以看到,我们常用的setState是定义在原型上的2个方法。
至此,一个
<App/>
组件已经有一个大概的雏形:到此为止了吗?这看了等于没看啊,究竟组件是怎么变成div的?render吗? 可是全局搜索,也没有一个function是render啊。
原来,我们的jsx语法会被
babel
编译的。这下清楚了,还用到了
React.createElement
通过
createElementWithValidation
,可以看到,return了一个element,这个element又是继承自
createElement
,接着往下找:这里又返回了一个
ReactElement
方法,再顺着往下找:诶,这里好像返回的就是
element
对象,再看我们最初的<App/>
的结构,是不是很像验证一下我们的探索究竟对不对,再每一个方法上我们都打上console,(注意,将App里的子元素全部删空,利于我们观察)
React.createElement 、 createElementWithValidation 、 createElement 、 ReactElement,通过这些方法,我们用class声明的React组件在变成真实dom之前都是
ReactElement
类型的js对象createElementWithValidation
:createElement
:ReactElement
:ReactElement就比较简单了,创建一个element对象,参数里的type、key、ref、props、等放进去,然后return了。最后调用Object.freeze使对象不可再改变。
组件的挂载
我们上面只是简单的探究了
<App/>
的结构和原理,那它究竟是怎么变成真实dom的呢我们接着用babel编译一下:
原来
ReactDOM.render
调用的是render方法,一样,找暴露出来的接口。它返回的是一个
legacyRenderSubtreeIntoContainer
方法,这次我们直接打上console.log这是打印出来的结果,
legacyRenderSubtreeIntoContainer 这个方法除主要做了两件事:
源码暂时只读到了这里,关于React16.1~3的新功能,以及新的生命周期的使用和原理、
Fiber
究竟是什么,我们将在后续文章接着介绍。广而告之
本文发布于薄荷前端周刊,欢迎Watch & Star ★,转载请注明出处。
欢迎讨论,点个赞再走吧 。◕‿◕。 ~