帮你更好了解React---手写简版React

2,017 阅读2分钟

先引入React创建demo看下效果,在引入简版的wxyReact看下效果

下面开始根据demo写代码

1. 原生组件处理逻辑

1.1 原生demo src/index.js 

//src/index.js

import React from './wxyReact'
import ReactDOM from './wxyReact/reactDom'
import './index.css'

const jsx = (<div className="dom">
    <div className='dd'>我是div组件</div>
</div>)

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

1.2 创建wxyReact

我们需要在里面做什么呢?wxyReact是react的属性

wxyReact含有什么呢?先运行demo看看,

可以通过错误信息得到我们的react需要一个createElement函数,

而参数假设通过源码中github.com/facebook/re…createElement函数312行得知返回为三个参数😝

是由于babel-loader默认编译,编译后的虚拟dom是如此 点击测试

so,我们就得到了wxyReact

👆👆👆👆上面的代码(方便复制)

//参数function createElement(type, props, ...children) {    //返回虚拟dom    //构建一个树状图,从父元素获取子元素,添加childern属性    props.children = children    //根据type不同,区分处理方式    let vtype;    if (typeof type === 'string') {        //原生标签<div></div><p></p>        vtype = 1    }    return {        type, props, vtype    }}const React = { createElement }export default React 

1.3 创建reactDom

reactDom是吧虚拟dom转换真实dom操作

在demo中可以观察到reactDom中包含render函数参数是node和父元素

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

👆👆👆👆上面的代码(方便复制)

import { initVnode } from './virtual-dom'function render(vnode, container) {    const node = initVnode(vnode, container)    //把真实的dom节点放到container里面去    container.appendChild(node)}const ReactDOM = { render }export default ReactDOM

初始化虚拟dom

👆👆👆👆上面的代码(方便复制)

//把vnode变成node export function initVnode(vnode, container) {    //查看vode解构区分节点渲染方式    let node = null;    const { vtype } = vnode    if (!vtype) {        node = initTexNode(vnode, container);    }    if (vtype === 1) {        //原生标签        node = initHtmlNode(vnode, container);    }    return node}function initTexNode(vnode, container) {    const node = document.createTextNode(vnode)    return node}function initHtmlNode(vnode, container) {    const { type, props } = vnode    const { children, ...rest } = props    const node = document.createElement(type)    props.children.map(item => {        node.appendChild(initVnode(item, node))    })    //添加标签属性    Object.keys(rest).map(key => {        if (key === 'className') {            node.setAttribute('class', rest[key])        }    })    return node}

效果如下

处理数组表达式渲染例如:

 {[1, 2, 3].map(one => `第${one}个、`)}

添加数组处理

    const { type, props } = vnode
    const { children, ...rest } = props
    const node = document.createElement(type)
    props.children.map(item => {
        //添加数组判断
      +  if (Array.isArray(item)) {
      +     for (let i of item) {
      +         node.appendChild(initVnode(i, node))
      +      }
        } else {
            node.appendChild(initVnode(item, node))
        }
    })

2. function函数处理逻辑

2.1添加function组件demo

//函数处理
+ function FuncCom(props) {
+    return <div >{props.name}</div>
+ }
const jsx = (<div className="dom">
    <div className='dd'>我是div组件</div>
+    <FuncCom name='function组件' />
</div>)

2.2 在wxyReact.js添加vtype判断

 let vtype;
    if (typeof type === 'string') {
        //原生标签<div></div><p></p>
        vtype = 1
+    } else if (typeof type === 'function') {
+       vtype =  3
+  }

2.3 在virtual-dom.js添加function dom 处理方法

function initFunctionNode(vnode, container) {    const { type, props } = vnode    console.log("TCL: initFunctionNode -> type", type)    //函数的虚拟dom    const vfnode = type(props)    //真实node    return initVnode(vfnode, container)}

效果如下:

3. class组件处理方法

3.1 class组件demo

class ClassCom extends React.Component {
    render() {
        return (
            <div>
                {this.props.name}
            </div>
        );
    }
}

const jsx = (<div className="dom">
    <div className='dd'>我是div组件</div>
    <FuncCom name='function组件' />
    <ClassCom name='class组件' />
</div>)

3.2在wxyReact.js添加vtype判断

咋判断呢,class也是函数组件,怎么区分函数组件和class组件呢?
veryEase如下:

3.3在virtual-dom.js添加class组件 dom 处理方法

效果如下:

4. 完整代码请前往github.com/XinYueXiao/…