英勇青铜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