React系列 --- 简单模拟语法(一)
React系列 --- Jsx, 合成事件与Refs(二)
React系列 --- virtualdom diff算法实现分析(三)
React系列 --- 从Mixin到HOC再到HOOKS(四)
React系列 --- createElement, ReactElement与Component部分源码解析(五)
React系列 --- 从使用React了解Css的各类使用方案(六)
React系列 --- 从零构建状态管理及Redux源码解析(七)
React系列 --- 扩展状态管理功能及Redux源码解析(八)算法
咱们先不讲什么语法原理,先根据API效果强行模拟语法使用,实现一个简易版的React.segmentfault
第一步咱们先用类建立一个元素返回,而且绑定点击事件,代码以下,能够正常看到一个按钮出现了.app
class AddButton { createDOM(domString) { const div = document.createElement("div"); div.innerHTML = domString; return div; } render() { this.dom = this.createDOM(`<button>0</button>`); this.dom.addEventListener("click", () => console.log("click"), false); return this.dom; } } document.body.appendChild(new AddButton().render());
实现类状态和修改状态方法dom
class AddButton { constructor() { this.state = { num: 0 }; } createDOM(domString) { const div = document.createElement("div"); div.innerHTML = domString; return div; } setState(state) { this.state = state; this.dom = this.render(); } handleAdd() { const num = this.state.num + 1; this.setState({ num: num }); } render() { this.dom = this.createDOM(`<button id="btn">${this.state.num}</button>`); this.dom.addEventListener("click", () => this.handleAdd(), false); console.log(this.dom); return this.dom; } } document.body.appendChild(new AddButton().render());
渲染以后看到this dom
输出已经发现改变了,可是视图并无渲染,那是由于这是结尾一次性插入,下面就渲染视图这块往下走this
咱们如今把插入数据的操做内置到class里面,新增一个方法插入新元素移除旧元素.code
class AddButton { constructor() { this.state = { num: 0 }; } createDOM(domString) { const div = document.createElement("div"); div.innerHTML = domString; return div; } changeDom() { const oDom = this.dom; this.dom = this.render(); document.body.insertBefore(this.dom, oDom); document.body.removeChild(oDom); } setState(state) { this.state = state; this.changeDom(); } handleAdd() { const num = this.state.num + 1; this.setState({ num: num }); } render() { this.dom = this.createDOM(`<button id="btn">${this.state.num}</button>`); this.dom.addEventListener("click", () => this.handleAdd(), false); return this.dom; } } document.body.appendChild(new AddButton().render());
如今效果虽然实现,可是仍是得开头手动把元素插入视图component
咱们先将一些共有方法提取到一个单独类继承
class Component { constructor() {} createDOM(domString) { const div = document.createElement("div"); div.innerHTML = domString; return div; } changeDom() { const oDom = this.dom; this.dom = this._render(); this.wrapper.insertBefore(this.dom, oDom); this.wrapper.removeChild(oDom); } setState(state) { this.state = state; this.changeDom(); } _render(wrapper) { if (wrapper) this.wrapper = wrapper; this.dom = this.createDOM(this.render()); this.dom.addEventListener("click", () => this.handleAdd(), false); return this.dom; } }
而后组件只须要直接继承Component
而后处理本身逻辑便可事件
class AddButton extends Component { constructor() { super(); this.state = { num: 0 }; } handleAdd() { const num = this.state.num + 1; this.setState({ num: num }); } render() { return `<button id="btn">${this.state.num}</button>`; } }
还有一个问题是点击事件暂时仍是耦合进Component
里面,先略过不提.rem
你们都知道React会提供这么一个方法将组件插入一个指定元素,咱们直接模拟
const ReactDom = { render(component, wrapper) { wrapper.appendChild(component._render(wrapper)); } }; ReactDom.render(new AddButton(), document.getElementById("root"));
还有一个重要的传输数据实现以下
const ReactDom = { render(component, wrapper) { wrapper.appendChild(component._render(wrapper)) } } class Component { constructor(props = {}) { this.props = props } createDOM(domString) { const div = document.createElement("div") div.innerHTML = domString return div } changeDom() { const oDom = this.dom this.dom = this._render() this.wrapper.insertBefore(this.dom, oDom) this.wrapper.removeChild(oDom) } setState(state) { this.state = state this.changeDom() } _render(wrapper) { if (wrapper) this.wrapper = wrapper this.dom = this.createDOM(this.render()) this.dom.addEventListener("click", () => this.handleAdd(), false) return this.dom } } class AddButton extends Component { constructor(props) { super(props) this.state = { num: 0 } } handleAdd() { const num = this.state.num + 1 this.setState({ num: num }) } render() { console.log(this.props) return `<button id="btn">${this.state.num}</button>` } } ReactDom.render(new AddButton({a:1}), document.getElementById("root"))
至此,抛开实际思路不说,咱们已经简单模拟出来React的通常语法实现了.