首页 > 其他分享 >#yyds干货盘点#React-初始化渲染

#yyds干货盘点#React-初始化渲染

时间:2023-11-06 10:38:51浏览次数:32  
标签:yyds dom DOM VNode React 干货 key props children

1.环境准备

初始化项目:npx create-react-app simple-react
删除一些代码,最关键的内容就是:
src/index.js
public/index.html
package.json中的dependencies和scripts:

2.JSX介绍

JSX是JavaScript的一种语法扩展。
JSX到普通Javascript的代码的转化是通过babel完成的。

3.React.createElement编写

DISABLE_NEW_JSX_TRANSFORM=true 禁用掉新的jsxdev转换,使用React.createElement

这个迷你的包(cross-env)能够提供一个设置环境变量的scripts,让你能够以unix方式设置环境变量,然后在windows上也能兼容运行。
npm i cross-env -D
package.json
"start": "cross-env DISABLE_NEW_JSX_TRANSFORM=true react-scripts start",

react17之前通过Babel把jsx转换为虚拟DOM
<div> Hello Simple React </div>
React.createElement("div", null, "Hello Simple React")

react.js

import { REACT_ELEMENT } from "./utils"
function createElement(type, properties, children) {
    // debugger
    let ref = properties.ref || null
    let key = properties.key || null

        // 属性可以是可读的、可写的或可删除的。
        // 属性可以是可枚举的(可以通过for…in循环枚举)或不可枚举的。
        // 可以通过Object.defineProperty()等方法定义属性的特性。
        ;['key', 'ref', '__self', '__source'].forEach(key => {
            delete properties[key]
        })
    let props = { ...properties }
    //传参大于3
    if (arguments.length > 3) {
        console.log(arguments)
        props.children = Array.prototype.slice.call(arguments, 2)
    } else {
        props.children = children
    }
    return {
        //$$--唯一性,jsx转换成为的类型
        $$typeof: REACT_ELEMENT,
        type,
        ref,//操作DOM
        key,//diff比较
        props
    }
}


const React = {
    createElement
}

export default React

4.ReactDOM.render函数编写

初始化渲染第一步:实现函数React.createElement
初始化渲染第二步:实现函数ReactDOM.render

react-dom.js

import { REACT_ELEMENT } from './utils'
//初始化渲染(不止挂载操作)
function render(VNode, containerDOM) {
    // 将虚拟DOM转化成真实DOM
    // 将得到的真实DOM挂载到contanerDOM中
    mount(VNode, containerDOM)
}
function mount(VNode, containerDOM) {
    let newDOM = createDOM(VNode)
    newDOM && containerDOM.appendChild(newDOM)
}
function createDOM(VNode) {
    // 1.根据类型创建元素 2.处理子元素,VNode是树形结构 3.处理属性值
    const { type, props } = VNode
    let dom;
    //typeof === REACT_ELEMENT代表虚拟DOM VNode
    if (type && VNode.$$typeof === REACT_ELEMENT) {
        dom = document.createElement(type)
    }

    if (props) {
        //子节点存在
        if (typeof props.children === 'object' && props.children.type) {
            //递归,创建子节点
            mount(props.children, dom)
        } else if (Array.isArray(props.children)) {
            //多个子节点
            mountArray(props.children, dom)
        } else if (typeof props.children === 'string') {
            //文本节点
            dom.appendChild(document.createTextNode(props.children))
        }
    }
    // TODO:处理属性值
    //setPropsForDOM(dom, props)
    return dom
}


//多个子节点处理
function mountArray(children, parent) {
    console.log('parent', parent, children)
    if (!Array.isArray(children)) return
    for (let i = 0; i < children.length; i++) {
        if (typeof children[i] === 'string') {
            //创建文本节点
            parent.appendChild(document.createTextNode(children[i]))
        } else {
            mount(children[i], parent)
        }
    }
}

const ReactDOM = {
    render
}

export default ReactDOM

5.实现函数setPropsForDOM进行属性更新

// 【这里需要注意jsx属性名称的写法】

ReactDOM.render(<div className='test-class' style={{color: 'red'}}>Simple React App<span>xx1</span><span>xx2</span></div>, document.getElementById('root'))
function setPropsForDOM(dom, VNodeProps = {}) {
    if (!dom) return
    for (let key in VNodeProps) {
        if (key === 'children') continue
        //^开头,on开头,A-Z之间一个,.匹配单个字符,
        //*号匹配一个字母或者数字出现一次或者多次 onclick
        if (/^on[A-Z].*/.test(key)) {
            // TODO: 事件处理
        } else if (key === 'style') {
            Object.keys(VNodeProps[key]).forEach(styleName => {
                dom.style[styleName] = VNodeProps[key][styleName]
            })
        } else {
            dom[key] = VNodeProps[key]
        }
    }
}

最后总结:从JSX源代码(<div>Hello JSX</div>)到显示到界面上,需要经历哪些关键环节。
JSX -> 转译成函数调用 -> 执行函数调用返回虚拟DOM -> 将虚拟DOM转化成DOM -> 将生成的DOM挂载到DOM上

标签:yyds,dom,DOM,VNode,React,干货,key,props,children
From: https://blog.51cto.com/u_11365839/8201880

相关文章

  • # yyds干货盘点 #3个Excel表格中每个门店物品不同,想要汇总在一起(方法四)
    大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Python自动化办公处理的问题,一起来看看吧。上一篇文章中,我们已经看到了三种解决办法了,这一篇文章我们一起来看看另外一种方法。二、实现过程这里【瑜亮老师】给了concat纵向合并的方式能操作的方法,代码如下......
  • React中状态提升
    代码案例functionA({onGetAName}){constname=`>${newDate().getTime()}<`;return(<div>ThisisAcomponent!{/*箭头函数形式来调用事件函数*/}<buttononClick={()=>onGetAName(name)}>sendAN......
  • # yyds干货盘点 # 读取xlsm格式的文件,该表格只有一个,但是通过python读取,却显示两个表
    大家好,我是皮皮。一、前言前几天在最强王者交流群【wen】问了一个Python处理Excel文件相关的问题,一起来看看吧。请教问题:读取xlsm格式的文件,该表格只有一个名字为"销售明细(2)"的表格,但是通过python读取该文件,却显示两个表格,分别为:“销售明细”和“销售明细(2)”df2=pd.read_excel(‘......
  • React学习笔记18-非受控组件
    1.非受控组件的定义非受控组件即状态不是完全由React的state来控制的组件React要编写一个非受控组件,可以使用ref来从DOM节点中获取表单数据,就是非受控组件。importReact,{Component}from'react'exportdefaultclassAppextendsComponent{myusername=R......
  • React学习笔记19-受控组件
    1.受控组件的定义React组件的数据渲染是否被调用者传递的props完全控制,完全控制则为受控组件,否则非受控组件。即React的state成为组件的唯一数据源。 下面用一个小案例来演示,案例中todolist组件的唯一数据源就是State,todolist组件就是一个受控组件importReact,{Com......
  • #yyds干货盘点#Expo 搭建 React-native 项目
    Expo搭建RN项目Expo 搭建项目有两种方式:一种是通过Expo的脚手架 expo-cli;一种是通过 create-react-native-app。本文采用第一种。1、安装expo-clinpminstallexpo-cli--global2、创建项目expoinitmy-new-project会有两类模板让你选择:托管工作流,裸露工作流(感觉叫原生工......
  • # yyds干货盘点 # 麻烦看下这个表格宏命令如何修复?
    大家好,我是皮皮。一、前言前几天在Python最强王者交流群【......
  • React学习笔记16-属性props
    1.属性的定义props是正常是外部传入的,组件内部也可以通过一些方式来初始化的设置,属性不能被组件自己更改,但是你可以通过父组件主动重新渲染的方式来传入新的props。这就是React中的单向数据流2.属性的特点属性是描述性质、特点的,组件自己不能随意更改,必须由父组件进行更改......
  • React学习笔记17-属性VS状态
    相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)不同点:1.属性能从父组件获取,状态不能2.属性可以由父组件修改,状态不能3.属性能在内部设置默认值,状态也可以,设置方式不一样4.属性不在组件内部修改,状态要在组件内部修改5.属性能设置子组件初始值......
  • React 中复制静态文件到 build的文件夹中
    React中复制静态文件到build的文件夹中环境:umi 框架前提:在跟目录下放置了Dockerfile 文件,在build时需要自动复制到dist文件夹里面。 1. 安装 copy-webpack-plugin 插件 2. .umirc.ts 文件中使用copy命令import{defineConfig}from"umi";exportdefaultde......