React源码(一): render && createElement

React源码——渲染(render && createElement)的简单实现

前言

当前市面上公司对React需求越来越大主, 对于React的源码学习必须提上日程

初始化项目

  1. React脚手架创建项目

    • 全局安装npm install -g create-react-app
    • 创建项目create-react-app My-React-App
    • 删除不需要的文件
  2. 目录文件如下
    在这里插入图片描述

  3. 运行热更新报错,解决方案React v17 热刷新 不起作用, 或者在package.json的脚本中加上 "start": "FAST_REFRESH=false react-scripts start",
    在这里插入图片描述

react创建以及分析创建虚拟dom,babel转化的原理babel试一试

  1. Jsx----->babel----->js方法------>React.createElement()------->vdom
    在这里插入图片描述

  2. React.createElement实现

// react.js
import get$$Type from './stants';

 /* @param type 元素类型
 * @param props 元素的配置对象
 * @param children 元素的子元素们
 */
function createElement(type,props,children){
    const { key, ref, ...resprops } = props ? props : {};
    const len = arguments.length;
    if(len > 3){
        // 多个children
        resprops.children = Array.prototype.slice.call(arguments,2)
    } else if(len === 3)r
        // children
        resprops.children = children;
    }else{
        // 没有children
        // do nothing
    }
    
    return {
        $$typeof:get$$Type(type),
        key,
        ref,
        type,
        props: resprops
    }
}

const React = {
    createElement
}

export default  React
// stants.js
const REACT_TEXT = Symbol("react.TEXT");
const REACT_ELEMENT = Symbol("react.element");
const get$$Type = (type) =>{
    return type ? REACT_ELEMENT : REACT_TEXT;
}
export default get$$Type

编写reactDOM.render方法,实现想虚拟dom转化成真实的dom

  1. vdom转化成真实dom
  2. 给真实dom赋值属性
  3. 递归childrenDom
  4. 内容append到对应的容器
// react-dom.js
// 渲染真是dom到页面
function render(vdom,container){
    const reldom = createDom(vdom);
    container.appendChild(reldom)
}

// 处理函数式组件
const mountFunctionComponent = (vdom) => {
    const { type ,props } = vdom;
    // 获取到函数的vdom
    let functionVdom = type(props);
    return createDom(functionVdom)
}

// 初始化以及更新属性
const updateOtherProps = (relDom,oldProps,newProps) => {
    if(newProps){
        for(let key in newProps){
            if(key === 'style'){
                for(let k in newProps[key]){
                    relDom.style[k] = newProps[key][k]
                }
            } else {
                relDom[key] = newProps[key]
            }
        }
    }
        
    // 更新处理
    if(oldProps){
        // 旧得属性在新的属性中没有删除
        for(let key in oldProps){
            if(!newProps[key]){
                relDom[key] = null
            }
        }
    }
}

const createDom = (vdom) => {
    let relDom;
    // 纯文本
    if(!vdom?.type){
        return document.createTextNode(vdom);
    }

    // ReactFragment 
    if( typeof vdom?.type === 'symbol'){
        return document.createTextNode(vdom?.props?.children);
    }
    const { type, props: { children,...resProps } } = vdom;

    // 函数组件
    if(typeof type == 'function') {
        // functionComponent---> 变成vdom
        return mountFunctionComponent(vdom)
    } else {
        // dom 节点
        relDom = document.createElement(type);
    }

    // 赋值属性
    if(resProps){
        updateOtherProps(relDom,{},resProps)
    }

    // 递归childrenDom
    if(children){
        renderChildren(children,relDom);
    }
    return relDom;
}


const renderChildren = (children,dom) => {
        // 多个children
        if(Array.isArray(children)){
            for(let index in children){
                render(children[index],dom)
            }
        } else {
            render(children,dom)
        }
}

const ReactDom = { render }
export default ReactDom


使用

import React from './react';
import ReactDOM from './react-dom';
import './index.css';

const  App = 
<div className='app' key='app' style={{ color:'peru',background:'mediumpurple' }}>
    <span style={{ color:'yellow' }}>
    app<b style={{ color:'plum' }}>7777</b>
    </span>
    <h3 style={{ color:'orange' }}>111</h3>
    <span style={{ color:'ghostwhite' }}>apps</span>
    333
    <>6666</>
</div>;
ReactDOM.render(App, document.getElementById('root'));

效果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值