手写react——青铜React

本文通过逐步实践,介绍了如何从零开始实现React的createElement和DOM渲染,从创建my-react脚手架,到理解虚拟DOM结构,编写自定义createElement和render函数,带你进入React世界的基础阶段。
摘要由CSDN通过智能技术生成

英勇青铜React

准备

随着使用时间的增加,我们对一个框架也会越来越熟悉,最终终归要对源码进行学习,这也是成为大佬的必经之路。

官方的脚手架create-react-app是一个比较适合用来学习的脚手架,所以我们在学习源码的时候都将在这个脚手架上编写代码。

create-react-app my-react

在使用create-react-app搭建好项目之后我们将src目录下除了index.js之外的所有文件全部删掉,然后将index.js中的所有内容也全部删掉。我们一步一步的来

实现

createElement

首先第一步,我们都知道react引入了虚拟dom的概念,而所谓的虚拟dom就是使用js对象去模拟dom节点组成一组虚拟dom树,然后再将树渲染成真实的dom节点,而这些虚拟dom就是使用createElement来创建的,我们可以先在index.js中写一个节点打印出来看一下虚拟dom的结构

// index.js
import React from 'react'

const a = (<div>hello</div>)

console.log(a)

//打印结果
{
    type: "div",
    key: null,
    ref: null,
    props: {
        children: "hello"
    }
}

从上面打印的信息我们就可以清楚的看到虚拟dom的结构,然后我们根据这个结构可以写出一个createElement的方法,我们写的代码全部放在my-react文件夹下,所以我们需要先创建一个my-react文件夹

|- src
    |- my-react
        |- react.js
    |- index.js

然后我们实现一个createElement

// my-react/react.js
const myReact = {
    createElement
}

function createElement(type, props, ...children){
    return {
        type,
        props: {
            ...props,
            children
        }
    }
}

export default myReact

我们在开发中并不会直接调用createElement方法,而是会写成jsx语法,增加代码的可读性,我们可以添加注释,告诉babel编译的时候使用我们指定的函数

// index.js

/** @jsxRuntime classic */
/** @jsx myReact.createElement */
import myReact from './my-react/react'

const container = document.getElementById('root')

const jsx = (
    <div>
        <h1>hello react</h1>
        <p>Welcome to React !</p>
    </div>
)

console.log(jsx)

ReactDOM.render

上面实现createElement之后我们就可以拿到虚拟dom的树状数据了,接下来就是将虚拟节点渲染到我们的页面上。我们再新建一个react-dom.js文件

|- src
    |- my-react
        |- react.js
        |- react-dom.js
    |- index.js
// my-react/react-dom.js
const ReactDOM = {
    render
}

function render(rootComponent, container){
    mount(rootComponent, container)
}

function mount(component, parentComponent){
    const el = createDOM(component)
    parentComponent.appendChild(el)
    const children = (component && component.props && component.props.children) || []
    
    children.forEach(item => {
        mount(item, el)
    })
}

function createDOM(node){
    const el = typeof node === 'object'
        ? document.createElement(node.type)
        : document.createTextNode(node)
    
    if(typeof node === 'object'){
        Object.keys(node.props)
        .filter(isProperty)
        .forEach(name => {
            el[name] = node.props[name]
        })
    }
        
    return el
}

export default ReactDOM

然后我们在index.js中执行render函数来渲染一下视图

// index.js
/** @jsxRuntime classic */
/** @jsx myReact.createElement */
import myReact from './my-react/react'
import ReactDOM from './my-react/react-dom'

const container = document.getElementById('root')

const jsx = (
  <div>
    <h1>hello react</h1>
    <p>Welcome to React !</p>
  </div>
)

ReactDOM.render(
  jsx,
  container
)

到这里我们就能看到页面上的内容渲染了出来

在这里插入图片描述

到这里就完成了一个青铜段位的react

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值