序言
一致使用react;一直想深入了解react运行机制
本周开始,跟着大神学习react源码
rander
获取虚拟DOM,调用createNode;将虚拟DOM生成为真实DOM
createNode
根据虚拟DOM的type类型将虚拟节点转换为真实节点;
- 如果虚拟DOM类型是number或者string,调用updateTextComponent
- 如果虚拟DOM的type类型为string,调用updateHostComponent
- 如果虚拟DOM的type类型为function,还要判断函数是否是reactComponent
- type.prototype.isReactComponent有值 调用updateClassComponent
- 如果type.prototype.isReactComponent没有值 调用updateFunctionComponent
- 其他类型判断为fragment标签,调用updateFragmentComponent
最后返回真实节点
updateTextComponent
调用document.createTextNode创建文本节点
function updateTextComponent(vnode) {
const node = document.createTextNode(vnode);
return node;
}
updateHostComponent
如果type是字符串表示什么意思呢?
type是字符串,表示type = 'div' 、a 、span 、 h1等html标签
通过调用 document.createElement 创建html节点
创建完html节点后,调用updateNode给html对象添加属性;
什么是html节点的属性呢?
- class
- id
- style
- key 等...
function updateHostComponent(vnode) {
const { type, props } = vnode;
const node = document.createElement(type);
updateNode(node, props);
reconcileChildren(node, props.children);
return node;
}
updateNode
function updateNode(node, nextValue) {
Object.keys(nextValue).filter((k) => k !== 'children').forEach((k) => {
node[k] = nextValue[k];
});
}
这里就比较好理解了,html节点是个对象,对象吗,[]可以添加属性了,将prop属性枚举给html节点即可
代码
//把vnode -> node并插入
// vnode 虚拟节点
// node 真是节点
function render(vnode, container) {
const node = createNode(vnode);
container.appendChild(node);
}
function isStringOrNumber(sth) {
return typeof sth === 'string' || typeof sth === 'number';
}
//将虚拟节点转换为真是节点
function createNode(vnode) {
console.log('vnode', vnode);
const { type } = vnode;
let node;
//原生标签节点
if (typeof type === 'string') {
node = updateHostComponent(vnode);
} else if (isStringOrNumber(vnode)) {
//文本标签
node = updateTextComponent(vnode);
} else if (typeof type === 'function') {
//类组件,函数组件
node = type.prototype.isReactComponent
? updateClassComponent(vnode)
: updateFunctionComponent(vnode);
} else {
// fragment标签
node = updateFragmentComponent(vnode);
}
return node;
}
function updateFragmentComponent(vnode) {
//const d =
const { props } = vnode;
const node = document.createDocumentFragment();
reconcileChildren(node, props.children);
return node;
}
//根据虚拟节点创建类组件
function updateClassComponent(vnode) {
const { type, props } = vnode;
const instance = new type(props);
const child = instance.render();
const node = createNode(child);
return node;
}
//根据虚拟节点创建函数组件
function updateFunctionComponent(vnode) {
const { type, props } = vnode;
const child = type(props);
const node = createNode(child);
return node;
}
//根据虚拟节点创建文本节点
function updateTextComponent(vnode) {
const node = document.createTextNode(vnode);
return node;
}
//根据虚拟节点生成原生标签节点,diva,p,h1
function updateHostComponent(vnode) {
const { type, props } = vnode;
const node = document.createElement(type);
updateNode(node, props);
reconcileChildren(node, props.children);
return node;
}
//更新原生标签属性和属性值
function updateNode(node, nextValue) {
Object.keys(nextValue)
.filter((k) => k !== 'children')
.forEach((k) => {
node[k] = nextValue[k];
});
}
// 处理子节点
function reconcileChildren(parentNode, children) {
//将children转换为数组
const newChildren = Array.isArray(children) ? children : [children];
for (let i = 0; i < newChildren.length; i++) {
const child = newChildren[i];
// vnode 变成node ;并将node插入parentNode
render(child || '', parentNode);
}
}
export default { render };