1. createElement,render方法的简易手写
\
index.js 要实现的功能:
import React, { Component } from "./mReact";
import ReactDOM from "./mReact-dom";
function Comp(props) {
return <h2>{props.name}</h2>;
}
const arrList = ["张三", "李四"];
class ClassComp extends Component {
render() {
return (
<div>
<p>{this.props.name}</p>
<p>
<span onClick={() => alert("点击了")} style={{ color: "red" }}>
内部文字
</span>
</p>
<ul>
{arrList.map(name => (
<li key={name}>{name}</li>
))}
</ul>
</div>
);
}
}
const jsx = (
<div id="demo">
<h1>Hello</h1>
<Comp name="函数组件" />
<ClassComp name="class组件" />
</div>
);
ReactDOM.render(jsx, document.getElementById("root"));
mReact.js: 简单实现 createElement方法
import { createVNode } from "./mvdom";
// React createElement方法
function createElement(type, props, ...children) {
props.children = children;
delete props.__source;
delete props.__self;
let vType; //用于指定类型,是原生标签,还是class组件还是函数组件
if (typeof type === "string") {
vType = 1;
} else if (typeof type === "function") {
vType = type.isClassComponent ? 2 : 3;//Component指定的静态属性isClassComponent,用于判断类型
}
return createVNode(vType, type, props); //返回虚拟dom的一部分属性,不是全部,主要是props
}
export default { createElement };
//只做简单处理
export class Component {
static isClassComponent = true; //判断是函数还是class
constructor(props) {
this.props = props;
this.state = {};
}
}
mReact-dom.js: 简单实现render方法,渲染dom
import { initNode } from "./mvdom";
// render方法 ReactDOM 将虚拟dom变成真实dom
function render(vnode, container) {
let node = initNode(vnode);
container.appendChild(node); //加到容器里面
}
export default { render };
mvdom.js:
//做个转化,返回json
export const createVNode = (vType, type, props) => {
return { vType, type, props };
};
// 转化虚拟dom为真实dom
export function initNode(vnode) {
const { vType } = vnode;
//为文本,不做处理,直接返回文本节点
if (!vType) {
return document.createTextNode(vnode);
}
if (vType === 1) {
return createNativeElement(vnode); //原生标签
} else if (vType === 2) {
return createClassElement(vnode); //class组件
} else if (vType === 3) {
return createFuncElement(vnode); //函数组件
}
}
//原生标签处理
function createNativeElement(vnode) {
const { props, type } = vnode;
let node = document.createElement(type); //创建元素,type就是div,span这种
const { children, key, ...rest } = props; //去除不是原生属性的
Object.keys(rest).forEach(attr => {
//特殊的进行处理
if (attr === "className") {
node.setAttribute("class", rest[attr]);
//特殊的进行处理
} else if (attr === "htmlFor") {
node.setAttribute("for", rest[attr]);
//style是Object进行处理,这里只是简单处理
} else if (attr === "style" && typeof rest[attr] === "object") {
let attrs = Object.keys(rest[attr])
.map(a => `${a}:${rest[attr][a]}`)
.join(";");
node.setAttribute(attr, attrs);
//事件处理
} else if (attr.startsWith("on")) {
node[attr.toLowerCase()] = rest[attr];
//其余属性的处理
} else {
node.setAttribute(attr, rest[attr]);
}
});
// children的里面的,进行递归处理
if (children && children.length > 0) {
children.forEach(chd => {
if (Array.isArray(chd)) {
//如果是数组,先进行拆分
chd.length > 0 &&
chd.forEach(element => {
node.appendChild(initNode(element)); //转化为真实dom,加到父节点里面
});
} else {
node.appendChild(initNode(chd)); //转化为真实dom,加到父节点里面
}
});
}
return node;
}
// class组件转化为真实dom
function createClassElement(vnode) {
const { type, props } = vnode;
let node = new type(props).render(); //class的render返回
return initNode(node); //最后都会回归到原生标签
}
// 函数组件转化为真实dom
function createFuncElement(vnode) {
const { type, props } = vnode;
let node = type(props); //函数直接执行即可
return initNode(node); //最后都会回归到原生标签
}
2. node-sass的安装 yarn配置
yarn config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/ -g
3. react-redux的connect的原理
import React, { Component } from "react";
import { MyContext } from "./context";
function connect(mapStateToProps, mapDispatchToProps) {
return function EnhanceHoc(WrappedComponent) {
class EnhanceComponent extends Component {
constructor(props, context) {
super(props);
this.state = {
storeState: mapStateToProps(context.getState()), //获取mapStateToProps要更新的state
};
}
componentDidMount() {
// 监听state的变化
this.subscribe = this.context.subscribe(() => {
//更新state触发页面的重新render
this.setState({
storeState: mapStateToProps(this.context.getState()),
});
});
}
componentWillUnmount() {
this.subscribe();
}
render() {
return (
<WrappedComponent
{...mapStateToProps(this.context.getState())}
{...mapDispatchToProps(this.context.dispatch)}
></WrappedComponent>
);
}
}
EnhanceComponent.contextType = MyContext; //获取context
return EnhanceComponent;
};
}
export { connect };
4. 上面 context.js的实现
import { createContext } from "react";
const MyContext = createContext();
export { MyContext };
5.上面的MyContext的使用方式
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { MyContext } from "./store/context";
// import { Provider} from "react-redux";
import store from "./store";
ReactDOM.render(
<MyContext.Provider value={store}>
<App />
</MyContext.Provider>,
document.getElementById('root')
);