React系列(二)--|React系列(二)-- React基本语法实现思路

前言 我们先不讲什么语法原理,先根据API效果强行模拟语法使用,实现一个简易版的React.
下面代码跟React源码没有关系,只是单纯模拟思路实现
render 第一步我们先用类创建一个元素返回,并且绑定点击事件,代码如下,可以正常看到一个按钮出现了.

class AddButton { // 创建Dom createDOM(domString) { const div = document.createElement("div"); div.innerHTML = domString; return div; }// 输出实例 render() { this.dom = this.createDOM(``); this.dom.addEventListener("click", () => console.log("click"), false); return this.dom; } }// 插入页面 document.body.appendChild(new AddButton().render());

state && setState 实现类状态和修改状态方法
class AddButton { // 内置状态 constructor() { this.state = { num: 0 }; }// 创建Dom 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(``); this.dom.addEventListener("click", () => this.handleAdd(), false); return this.dom; } }// 插入页面 document.body.appendChild(new AddButton().render());

渲染之后看到this.dom输出已经发现改变了,但是视图并没有渲染,那是因为这是结尾一次性插入,下面就渲染视图这块往下走
重新渲染 我们现在把插入数据的操作内置到class里面,新增一个方法插入新元素移除旧元素.
class AddButton { // 内置状态 constructor() { this.state = { num: 0 }; }// 创建Dom 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(``); this.dom.addEventListener("click", () => this.handleAdd(), false); return this.dom; } }// 插入页面 document.body.appendChild(new AddButton().render());

现在效果虽然实现,但是还是得开头手动把元素插入视图
抽取公用类 我们先将一些共有方法提取到一个单独类,另外补全一下props属性传参
class React { // 内置状态 constructor(props = {}) { // 实例 this.wrapper = null // 状态 this.state = {} // 属性 this.props = {} }// 创建Dom 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", () => console.log('添加自定义事件'), false); return this.dom; } }

然后组件只需要直接继承Component然后处理自己逻辑即可
class AddButton extends React { constructor() { super(); this.state = { num: 0 }; }handleAdd() { const num = this.state.num + 1; this.setState({ num: num }); }render() { return ``; } }

上面做了几件事:
  1. 抽取通用的逻辑到React类
  2. 自定义组件AddButton
还有一个问题是点击事件暂时还是耦合进Component里面,下一章节实现
添加自定义事件 因为事件是由组件自定义的,所以我们思路是在组件实例定义好之后,通用类绑定事件
class React { // 内置状态 constructor(props = {}) { // 实例 this.wrapper = null // 状态 this.state = {} // 属性 this.props = {} // 事件 this.event = {} }// 创建Dom 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(); }// 初始化事件 initEvent() { const events = Object.keys(this.event) events.forEach(key => { this.dom.addEventListener(key, this.event[key].bind(this), false); }) }// 输出实例 _render(wrapper) { if (wrapper) this.wrapper = wrapper; this.dom = this.createDOM(this.render()); // 需要创建实例后才能初始化 this.dom && this.initEvent() return this.dom; } }

同时组件代码也需要相对应的修改
class AddButton extends React { constructor() { super(); this.state = { num: 0 }; this.event = { click: this.handleAdd } }handleAdd() { const num = this.state.num + 1; this.setState({ num: num }); }render() { return ``; } }

ReactDom.render 【React系列(二)--|React系列(二)-- React基本语法实现思路】大家都知道React会提供这么一个方法将组件插入一个指定元素,我们直接模拟
const ReactDom = { // 指定元素内插入组件实例 render(component, wrapper) { wrapper.appendChild(component._render(wrapper)); } };

最终运行代码 我们上面已经实现了几个功能:
  1. 负责创建元素的React类,包括单向数据流,自定义状态,事件,替换元素等
  2. 负责挂载的ReactDom类

至此,抛开实际思路不说,我们已经简单模拟出来React的基本语法实现了.

    推荐阅读