React.createElement和ReactDom.render方法简单思路

2022-10-25 14:00:13 浏览数 (1)

实际上,JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖,因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成。

例如,用 JSX 编写的代码:

代码语言:javascript复制
class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.toWhat}</div>;
  }
}

ReactDOM.render(
  <Hello toWhat="World" />,
  document.getElementById('root')
);

可以编写为不使用 JSX 的代码:

代码语言:javascript复制
import { TEXT } from "../lreact/constant";


function createElement(type,config,...children){
    // createElement 就是生成 {type:'xxx',children:[]}结构对象
    if(config){
        delete config.__self;
        delete config.__source;
    }

    let props={
        ...config,
        children:children.map(Child=>typeof Child==='object'?Child:createChild(Child))
    }
    return {
        type,
        props
    }
}
function createChild(text){
    return {
        type:TEXT,
        props:{
            nodeValue:text,
            children:[]
        }
    }
}
export class Component{
    static isReactComponent={}
    constructor(props){
        this.props=props;
    }
}

export default {
    createElement,
    Component
}

ReactDom.render实现

代码语言:javascript复制
export const TEXT='text';
export const PLACEMENT="PLACEMENT";
export const UPDATE="UPDATE";
export const DELETION="DELETION"


// 正在处理的根fiber
let workInProgressRoot = null
// 下一个要处理的fiber
let nextUtilOfFiber = null
function render(vnode, container) {
    // 此处要生成根fiber
    workInProgressRoot = {
        base:null,
        node:container,
        props: {
            children: [vnode]
        }
    }
    nextUtilOfFiber=workInProgressRoot;
}   




function createNode(fiber){
    const {type,props}=fiber;
    let node=null;
    if(type===TEXT){
        node=document.createTextNode(props.nodeValue);
    }else if(typeof type==='string'){
        node=document.createElement(type);
    }

    updateProps(node,props);
    return node;
    
}
// 更新所有的props除了children
function updateProps(node,props){
    Object.keys(props).filter(i=>i!=='children').forEach(i=>node[i]=props[i])
}
function updateHostComponent(fiber){
    if(!fiber.node){
        fiber.node=createNode(fiber);
    }
   // 协调children
   const { children } = fiber.props
   reconcileChildren(fiber, children)

}

// 协调
function reconcileChildren(workInProgress,children){

    let preFiber=null;
    for(let i=0;i<children.length;i  ){
        let child=children[i];
        let newFiber={
            type:child.type,
            props:child.props,
            node:null,
            base:null,
            return:workInProgress,
            effectTag: PLACEMENT
        }
        if(i===0){
            workInProgress.child=newFiber
        }else{
            preFiber.sibling=newFiber
        }
        preFiber=newFiber;
    }
}
function updateFunctionComponent(fiber){
    const {type}=fiber;
    let vnode=type(fiber.props);
    reconcileChildren(fiber,[vnode]);
}
function updateClassComponent(fiber){
    const {type}=fiber;
    let vnode=new type(fiber.props);
    reconcileChildren(fiber,[vnode.render()]);
}
// 处理这个fiber,并且返回一个fiber
function preNextUtilOfFiber(fiber) {
    const {type}=fiber;
    if(typeof type==='function'){
        // 函数或者类组件
        type.isReactComponent?updateClassComponent(fiber):updateFunctionComponent(fiber)
    }else{
        // 处理h5标记的fiber,并且协调儿子们
        updateHostComponent(fiber);
    }
    // 有儿子先处理儿子
    if(fiber.child){
        return fiber.child;
    }
    console.log(fiber,99)
    // 没儿子先处理弟弟,没弟弟找爸爸的弟弟
    let nextFiber=fiber;
    while(nextFiber){
        if(nextFiber.sibling){
            return nextFiber.sibling;
        }
        nextFiber=nextFiber.return;
    }
    return null;


}
function commitWorker(fiber){
    if(!fiber){
        return ;
    }

    // 找到最近的有真实dom的fiber
    let parnetNodeFiber=fiber.return;
    while(!parnetNodeFiber.node){
        parnetNodeFiber=parnetNodeFiber.return;
    }
    // 将当前faber的node追加到付类
    const parentNode=parnetNodeFiber.node;
    if (fiber.effectTag === PLACEMENT && fiber.node !== null) {
        // 如果有fiber.node加入到父节上
    
        parentNode.appendChild(fiber.node);
    }
    // 一人得道,鸡犬声跳呢
    commitWorker(fiber.child)
    commitWorker(fiber.sibling)
    
}
function commitRoot() {
    commitWorker(workInProgressRoot.child);
    workInProgressRoot = null;

}





function workLoop(lealine) {
    while (nextUtilOfFiber && lealine.timeRemaining() > 1) {
        console.log(nextUtilOfFiber)
        nextUtilOfFiber = preNextUtilOfFiber(nextUtilOfFiber);
    }
    if (!nextUtilOfFiber && workInProgressRoot) {
        console.log(workInProgressRoot)
        commitRoot()
    }
    requestIdleCallback(workLoop)
}

requestIdleCallback(workLoop)

export default {
    render
}

0 人点赞