对react的研究20200723

JSX
在线尝试
1. 什么是JSX
语法糖
React 使⽤ JSX 来替代常规的 JavaScript。
JSX 是⼀个看起来很像 XML 的 JavaScript 语法扩展。
2. 为什么需要JSX
开发效率:使⽤ JSX 编写模板简单快速。
执⾏效率:JSX编译为 JavaScript 代码后进⾏了优化,执⾏更快。
类型安全:在编译过程中就能发现错误。
3. 原理:babel-loader会预编译JSX为React.createElement(...)
4. 与vue的异同:
react中虚拟dom+jsx的设计⼀开始就有,vue则是演进过程中才出
现的
jsx本来就是js扩展,转义过程简单直接的多;vue把template编译
为render函数的过程需要复杂的编译器转换字符串-ast-js函数字符
JSX预处理前:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./index.css";
function FuncCmp(props) {
return <div>name: {props.name}</div>;
}
class ClassCmp extends Component {
render() {
return <div>name: {this.props.name}</div>;
}
}
const jsx = (
<div>
<p>我是内容</p>
<FuncCmp name="我是function组件" />
<ClassCmp name="我是class组件" />
</div>
);
console.log("jsx", jsx);
ReactDOM.render(jsx, document.getElementById("root"));
build后
function FuncCmp(props) {
return React.createElement(
"div",
null,
"name: ",
props.name
);
}
class ClassCmp extends React.Component {
render() {开课吧web全栈工程师
return React.createElement(
"div",
null,
"name: ",
this.props.name
);
}
}
 
let jsx = React.createElement(
"div",
null,
" ",
React.createElement(
"div",
{ className: "border" },
"我是内容"
),
" ",
React.createElement(FuncCmp, { name: "我是function组件"
}),
" ",
React.createElement(ClassCmp, { name: "我是class组件" }),
" "
);
ReactDOM.render(jsx, document.getElementById('root'));
 
实现三⼤接⼝:React.createElement,
React.Component, ReactDom.render
 
CreateElement
将传⼊的节点定义转换为vdom。
src/index.js
 
// import React, { Component } from "react";
// import ReactDOM from "react-dom";
import React from "./kreact/";
import ReactDOM from "./kreact/ReactDOM";
import "./index.css";
function FuncCmp(props) {
return <div>name: {props.name}</div>;
}
class ClassCmp extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
}
clickHandle = () => {
console.log("clickHandle");
};
render() {
const { counter } = this.state;
return (
<div>
name: {this.props.name}
<p>counter: {counter}</p>
<button onCclick={this.clickHandle}>点击</button>
{[0, 1, 2].map(item => {
return <FuncCmp name={"我是function组件" + item}
key={item} />;
})}
</div>
);
}
}
let jsx = (开课吧web全栈工程师
<div>
<div className="border">我是内容</div>
<FuncCmp name="我是function组件" />
<ClassCmp name="我是class组件" />
</div>
);
ReactDOM.render(jsx, document.getElementById("root"));
 
创建./src/kkreact/index.js,它需要包含createElement⽅法
import { Component } from "./Component";
function createElement(type, props, ...children) {
props.children = children;
//判断组件类型
let vtype;
if (typeof type === "string") {
// 原⽣标签
vtype = 1;
} else if (typeof type === "function") {
// 类组件 函数组件
vtype = type.isReactComponent ? 3 : 2;
}
return {
vtype,
type,
props,
};
}
const React = {
createElement,
Component,
};
export default React;
 
render
创建react-dom.js
需要实现⼀个render函数,能够将vdom渲染出来,这⾥先打印vdom
结构
import { mount } from "./virtual-dom";
function render(vnode, container) {
//vnode->node
mount(vnode, container);
// container.appendChild(node)
console.log("render", vnode);
}
export default {
render,
};
实现Component
 
要实现class组件,需要添加Component类,kreact.js
export class Component {
static isReactComponent = {};
constructor(props) {
this.props = props;
this.state={}
}
}
组件类型判断
传递给createElememnt的组件有三种组件类型,1:dom组件, 2. class
组件, 3. 函数组件,使⽤vtype属性标识
转换vdom为真实dom
export function mount(vnode, container) {
const { vtype } = vnode;
//创建⽂本节点
if (!vtype) {
mountText(vnode, container);
}
// 创建原⽣节点
if (vtype === 1) {
mountHtml(vnode, container);
}
// 创建函数组件
if (vtype === 2) {
mountFunc(vnode, container);
}开课吧web全栈工程师
//创建类组件
if (vtype === 3) {
mountClass(vnode, container);
}
}
function mountText(vnode, container) {
const textNode = document.createTextNode(vnode);
container.appendChild(textNode);
}
// 创建原⽣节点
function mountHtml(vnode, container) {
const { type, props } = vnode;
const node = document.createElement(type);
const { children, ...rest } = props;
Object.keys(rest).map(item => {
if (item === "className") {
node.setAttribute("class", rest[item]);
} else if (item.slice(0, 2) === "on") {
node.addEventListener("click", rest[item]);
}
});
children.map(item => {
if (Array.isArray(item)) {
item.map(c => {
mount(c, node);
});
} else {
mount(item, node);
}
});
container.appendChild(node);
}开课吧web全栈工程师
// 创建函数组件
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);
}
执⾏渲染,kreact-dom.js
import { mount } from "./virtual-dom";
function render(vnode, container) {
//vnode->node
mount(vnode, container);
// container.appendChild(node)
console.log("render", vnode);
}
export default {
render,
};
总结:
1. webpack+babel编译时,替换JSX为
React.createElement(type,props,...children)开课吧web全栈工程师
2. 所有React.createElement()执⾏
结束后得到⼀个JS对象即vdom,它能
够完整描述dom结构
3. ReactDOM.render(vdom, container)可以将vdom转换为dom并追加
到container中
4. 实际上,转换过程需要经过⼀个diffff过程,⽐对出实际更新补丁操作dom
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2020-07-23 16:21  又回到了起点  阅读(151)  评论(0编辑  收藏  举报