preact源码分析(二)

image

image

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文件, 从我们目前已知的内容, 可以总结出以下的内容。

image

image

forceUpdate会在以后的文章中介绍。

猜你喜欢

转载自juejin.im/post/5c9759cef265da611256430c