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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: react源码解析手写ReactDom.js和React

前言

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


创建项目

首先npx create-react-app xxx


降为17

"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"
  },

环境

React 17.0.2


目录结构

image.png


实现的功能

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

let jsx = (
  <div>
    <div className='geyao'>我是歌谣</div>
    <FuncGeyao name="geyao"></FuncGeyao>
    <ClassGeyao name="geyao"></ClassGeyao>
  </div>
)
ReactDOM.render(jsx, document.getElementById('root'));

局部实现代码

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)
}

数组遍历的实现

Object.keys(rest).map(item=>{
        if(item==='className'){
            node.setAttribute("class",rest[item])
        }
    })

方法监听的实现

Object.keys(rest).map(item=>{
        if(item.slice(0,2)==="on"){
            node.addEventListener("click",rest[item])
        }
    })



核心代码

主入口 index.js

/** @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)

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

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
}

运行结果


image.png

相关文章
|
8天前
|
JavaScript 前端开发 Go
CSS 与 JS 对 DOM 解析和渲染的影响
【10月更文挑战第16天】CSS 和 JS 会在一定程度上影响 DOM 解析和渲染,了解它们之间的相互作用以及采取适当的优化措施是非常重要的。通过合理的布局和加载策略,可以提高网页的性能和用户体验,确保页面能够快速、流畅地呈现给用户。在实际开发中,要根据具体情况进行权衡和调整,以达到最佳的效果。
|
13天前
|
前端开发 JavaScript
React Hooks 全面解析
【10月更文挑战第11天】React Hooks 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性,简化了状态管理和生命周期管理。本文从基础概念入手,详细介绍了 `useState` 和 `useEffect` 的用法,探讨了常见问题和易错点,并提供了代码示例。通过学习本文,你将更好地理解和使用 Hooks,提升开发效率。
43 4
|
15天前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
5天前
|
存储 前端开发 JavaScript
JavaScript垃圾回收机制深度解析
【10月更文挑战第21】JavaScript垃圾回收机制深度解析
86 59
|
2天前
|
监控 前端开发 JavaScript
React 静态网站生成工具 Next.js 入门指南
【10月更文挑战第20天】Next.js 是一个基于 React 的服务器端渲染框架,由 Vercel 开发。本文从基础概念出发,逐步探讨 Next.js 的常见问题、易错点及解决方法,并通过具体代码示例进行说明,帮助开发者快速构建高性能的 Web 应用。
22 10
|
1天前
|
资源调度 前端开发 数据可视化
构建高效的数据可视化仪表板:D3.js与React的融合之道
【10月更文挑战第25天】在数据驱动的时代,将复杂的数据集转换为直观、互动式的可视化表示已成为一项至关重要的技能。本文深入探讨了如何结合D3.js的强大可视化功能和React框架的响应式特性来构建高效、动态的数据可视化仪表板。文章首先介绍了D3.js和React的基础知识,然后通过一个实际的项目案例,详细阐述了如何将两者结合使用,并提供了实用的代码示例。无论你是数据科学家、前端开发者还是可视化爱好者,这篇文章都将为你提供宝贵的洞见和实用技能。
12 5
|
14天前
|
JavaScript 前端开发 索引
JavaScript ES6及后续版本:新增的常用特性与亮点解析
JavaScript ES6及后续版本:新增的常用特性与亮点解析
14 4
|
16天前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
39 5
|
18天前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
|
18天前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)

推荐镜像

更多