前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React.createElement和ReactDom.render方法简单思路

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

作者头像
刘嘿哈
发布2022-10-25 14:00:13
2700
发布2022-10-25 14:00:13
举报
文章被收录于专栏:js笔记
实际上,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
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实际上,JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖,因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档