前言
大家好 我是歌谣 今天给大家带来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
目录结构
实现的功能
原生标签和类组件和函数组件的渲染
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 }
运行结果