前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >react源码解析手写ReactDom.js和React

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

作者头像
爱学习的前端歌谣
发布2023-10-19 14:49:20
1410
发布2023-10-19 14:49:20
举报
文章被收录于专栏:前端小歌谣前端小歌谣

前言

大家好 我是歌谣 今天给大家带来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
}

运行结果

总结

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小歌谣 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档