react源码解析手写ReactDom.js和React

2023-10-19 14:49:20 浏览数 (2)

前言

大家好 我是歌谣 今天给大家带来react源码部分的实现

环境

React 17.0.2

目录结构

创建项目

首先npx create-react-app xxx

降为17

代码语言:javascript复制
"dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },

实现的功能

原生标签和类组件和函数组件的渲染

代码语言:javascript复制
let jsx = (
  <div>
    <div className='geyao'>我是歌谣</div>
    <FuncGeyao name="geyao"></FuncGeyao>
    <ClassGeyao name="geyao"></ClassGeyao>
  </div>
)
ReactDOM.render(jsx, document.getElementById('root'));

局部实现代码

代码语言:javascript复制
function mount(vnode, container) {
    const { vtype } = vnode
    if (!vtype) {
        mountTextNode(vnode, container) //处理文本节点
    }
    if (vtype == 1) {
        mountHtml(vnode, container) //处理原生标签
    }
    if(vtype===3){ //处理函数组件
        mountFunc(vnode, container)
    }
    if(vtype===2){ //处理类组件
        mountClass(vnode, container)
    }
}
function mountTextNode(vnode, container) {
    const node = document.createTextNode(vnode)
    container.appendChild(node)
}
function mountHtml(vnode, container) {
    const { type, props } = vnode
    var node = document.createElement(type)
    const { children,...rest } = props
    children.map(item => {
        if(Array.isArray(item)){
            item.map(c=>{
                mount(c,node)
            })
        }else{
            mount(item, node)
        }
        // mount(item, node)
    
    })
    Object.keys(rest).map(item=>{
        if(item==='className'){
            node.setAttribute("class",rest[item])
        }
        if(item.slice(0,2)==="on"){
            node.addEventListener("click",rest[item])
        }
    })
    container.appendChild(node)
}
function mountFunc(vnode, container){
    const {type,props}=vnode
    const node=type(props)
    mount(node,container)
}
function mountClass(vnode, container){
    const {type,props}=vnode
   const cmp=new type(props)
   const node=cmp.render()
    mount(node,container)
}

数组遍历的实现

代码语言:javascript复制
Object.keys(rest).map(item=>{
        if(item==='className'){
            node.setAttribute("class",rest[item])
        }
       
    })

方法监听的实现

代码语言:javascript复制
   Object.keys(rest).map(item=>{
        if(item.slice(0,2)==="on"){
            node.addEventListener("click",rest[item])
        }
    })

核心代码

主入口 index.js

代码语言:javascript复制
/** @jsxRuntime classic */
import ReactDOM from './kreact/ReactDom';
import React from "./kreact"
import './index.css';
function FuncGeyao(props) {
  return <div className='geyao'>
    name:{props.name}
    
  </div>
}
class ClassGeyao extends React.Component {
  handle=()=>{
    console.log("geyaoisnice")
  }
  render() {
    return <div onClick={this.handle} className='geyao'>我是芳芳
    
    {[0,1,2].map(item=>{
      return <FuncGeyao key={item} name={"geyao" item}></FuncGeyao>
    })}
  
    </div>
  }
}
let jsx = (
  <div>
    <div className='geyao'>我是歌谣</div>
    <FuncGeyao name="geyao"></FuncGeyao>
    <ClassGeyao name="geyao"></ClassGeyao>
  </div>
)


ReactDOM.render(jsx, document.getElementById('root'));

index.js(React)

代码语言:javascript复制
function createElement(type,props,...children){
    console.log(arguments,"createElement")
    console.log(type,props,children,"children")
    props.children=children;
    let vtype;
    if(typeof type==="string"){
        vtype=1;
    }
    if(typeof type==="function"){
        vtype=type.isReactComponent?2:3
    }
    return {
        vtype,
        type,
        props
    }
}
 class Component{
    static isReactComponent={}
    constructor(props){
        this.props=props
    }
}
export default{
    Component,
    createElement
}

ReactDom.js

代码语言:javascript复制
function render(vnode, container) {
    console.log("enter", vnode)
    mount(vnode, container)
}
function mount(vnode, container) {
    const { vtype } = vnode
    if (!vtype) {
        mountTextNode(vnode, container) //处理文本节点
    }
    if (vtype == 1) {
        mountHtml(vnode, container) //处理原生标签
    }
    if(vtype===3){ //处理函数组件
        mountFunc(vnode, container)
    }
    if(vtype===2){ //处理类组件
        mountClass(vnode, container)
    }
}
function mountTextNode(vnode, container) {
    const node = document.createTextNode(vnode)
    container.appendChild(node)
}
function mountHtml(vnode, container) {
    const { type, props } = vnode


    var node = document.createElement(type)
    const { children,...rest } = props
    children.map(item => {
        if(Array.isArray(item)){
            item.map(c=>{
                mount(c,node)
            })
        }else{
            mount(item, node)
        }
        // mount(item, node)
      
    })
    Object.keys(rest).map(item=>{
        if(item==='className'){
            node.setAttribute("class",rest[item])
        }
        if(item.slice(0,2)==="on"){
            node.addEventListener("click",rest[item])
        }
    })
    container.appendChild(node)
}
function mountFunc(vnode, container){
    const {type,props}=vnode
    const node=type(props)
    mount(node,container)
}
function mountClass(vnode, container){
    const {type,props}=vnode
   const cmp=new type(props)
   const node=cmp.render()
    mount(node,container)
}


export default {
    render
}

运行结果

总结

我是歌谣 最好的种树是十年前 其次是现在 多看 多写 多输出 这是源码功能实现的部分代码 后续持续优化

0 人点赞