preact原始碼分析(一)

利維亞的傑洛特發表於2019-03-24

image

image

前言

我在寫這篇文章的時候, 原始碼也只是看了一部分, 而且有一些部分也不是非常的明白清除。各位看官還請酌情參考。發現錯誤還請指出。

什麼是preact?

官方給出的定義如下Fast 3kB React alternative with the same modern API. Components & Virtual DOM.。preact是react的精簡實現。廢話少說, 接下來我們直接看preact的原始碼。

src/create-element.js

create-element.js裡一共定義了5個方法, 我們在這裡先討論其中的3個。其餘的方法會在後序的文章中涉及。

createElement && createVNode

createElement和createVNode一同實現了建立VNode節點的功能。createElement一共有三個引數, type, props, children。

type引數為建立VNode的型別。根據原始碼中type引數的d.ts的定義檔案可知, type可以為String型別和Function型別或者Null。String型別對應著普通的DOM節點, Function型別則對應的Preact元件。

props引數為VNode的屬性, 同時對應著元件的Props。

children引數VNode的子節點, 在這裡沒有規定children引數的個數, VNode可以擁有一組子節點。

export function createElement(type, props, children) {
  // 對props做出容錯處理, 設定props的預設值
  if (props==null) props = {};
  
  // 對多餘的引數建立一個children的陣列, 陣列中存放著VNode的子節點
	if (arguments.length>3) {
		children = [children];
		for (let i=3; i<arguments.length; i++) {
			children.push(arguments[i]);
		}
  }
  ‘
  // 將children掛載到props上
	if (children!=null) {
		props.children = children;
	}

  // 如果Function型別的type存在defaultProps屬性(預設的props可以引數React中用法)
  // 將其每一個屬性掛載到props上
	if (type!=null && type.defaultProps!=null) {
		for (let i in type.defaultProps) {
			if (props[i]===undefined) props[i] = type.defaultProps[i];
		}
  }
  
  // 從props中單獨取出ref和key屬性
	let ref = props.ref;
	if (ref) delete props.ref;
	let key = props.key;
  if (key) delete props.key;
  
  // 將處理後的引數交由createVNode函式處理
	return createVNode(type, props, null, key, ref);
}

複製程式碼

createVNode函式更為簡單, 它會建立VNode物件並返回它。

其中text引數對應中文字節點中, 文字內容。

export function createVNode(type, props, text, key, ref) {
	const vnode = {
		type,
		props,
		text,
		key,
		ref,
		_children: null,
		_dom: null,
		_lastDomChild: null,
		_component: null
	};

	if (options.vnode) options.vnode(vnode);

	return vnode;
}
複製程式碼

coerceToVNode

通過函式的名稱可得知, coerceToVNode函式會將一些非VNode的節點轉化為VNode節點


export function coerceToVNode(possibleVNode) {
  // boolean型別和null返回null
	if (possibleVNode == null || typeof possibleVNode === 'boolean') {
    return null;
  }
  // string型別和number型別返回text的Vnode節點
	if (typeof possibleVNode === 'string' || typeof possibleVNode === 'number') {
		return createVNode(null, null, possibleVNode, null, null);
	}

  // 對於陣列將會使用Fragment做一層包裝
	if (Array.isArray(possibleVNode)) {
		return createElement(Fragment, null, possibleVNode);
  }
  
  // 如果本身屬於Vnode節點將會返回一個clone的Vnode節點
	if (possibleVNode._dom!=null) {
		return createVNode(possibleVNode.type, possibleVNode.props, possibleVNode.text, possibleVNode.key, null);
	}

	return possibleVNode;
}
複製程式碼

結語

截止目前據我們所知的VNode節點如下。在下一篇文章中我們將學習component.js檔案。

image

其他

preact原始碼分析(一)

preact原始碼分析(二)

preact原始碼分析(三)

preact原始碼分析(四)

preact原始碼分析(五)

相關文章