src/component.js
component.js文件中定义了Preact中Component类。因为我们还没有涉及到Diff算法, 所以目前在这里只会介绍文件中的一部分代码, 其余的部分在接下来文章中会得到补充。
constructor
Component类的定义, Component类中定义了两个参数, props以及context。props为初始化组件的参数, context为父组件的上下文。
export function Component(props, context) {
this.props = props
this.context = context
}
复制代码
setState
setState方法中会初始化名为"_nextState"的属性。_nextState属性确保了每一次的setState都将在setState内部生成一个浅拷贝的对象。
Component.prototype.setState = function(update, callback) {
// 在第一次初始化组件的时, _nextState为undefined, 所以将执行或语句的后半句
// this._nextState = assign({}, this.state), this._nextState将会被初始化
let s = (this._nextState!==this.state && this._nextState) || (this._nextState = assign({}, this.state));
// 在这里同React一样setState将会接受两种类型的参数, Object和Function类型
// 如果是Object类型, 将会执行一层浅拷贝
// 如果是Function类型, 则会把现在state和props传入函数, 返回的对象将作为执行一层浅拷贝
if (typeof update!=='function' || (update = update(s, this.props))) {
assign(s, update);
}
if (update==null) return;
// 如果有setState存在第二个参数, 将会把callback保存到_renderCallbacks的数组中
if (callback) this._renderCallbacks.push(callback);
// 将组件传入处理组件重新渲染(render)的队列中处理
enqueueRender(this);
};
复制代码
q
q定义了一个渲染(render)的队列
let q = []
复制代码
defer
defer将会返回一个Promise.resolve()的回调。
const defer = typeof Promise=='function' ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout;
复制代码
let foo = function () {
return 'Hello World'
}
// Promise {<resolved>: "Hello World"}
defer(foo)
复制代码
enqueueRender
enqueueRender函数会将需要render的组件push到q队列中。并根据条件判断是否需要渲染组件。
为什么说setState是一个异步的过程, 可以从这里得到答案, defer将会返回一个Promise.resolve()对象。
export function enqueueRender(c) {
// 只有当_dirty为false时, 并且队列的长度为1的情况下才会处理队列
if (!c._dirty && (c._dirty = true) && q.push(c) === 1) {
(options.debounceRendering || defer)(process);
}
}
复制代码
process
process函数中将会遍历q队列, 调用forceUpdate方法重新渲染组件。
function process() {
let p;
// 迭代将会在q队列被清空时结束
while ((p=q.pop())) {
// 只有当_dirty为true时才会更新组件, forceUpdate方法因为涉及到diff算法的内容这里暂不涉及
if (p._dirty) p.forceUpdate(false)
}
}
复制代码
render
render函数接受props和state返回需要更新的Dom树。
render函数默认Fragment。Fragment在create-element.js中定义为空函数, Fragment可以用来包裹一组节点。具体作用可以参考React中Fragment。
Component.prototype.render = Fragment;
复制代码
结语
目前我们简略的概览component文件, 从我们目前已知的内容, 可以总结出以下的内容。
forceUpdate会在以后的文章中介绍。