资讯专栏INFORMATION COLUMN

React系列 --- 简单模拟语法(一)

piglei / 1254人阅读

摘要:系列系列简单模拟语法一系列合成事件与二系列算法实现分析三系列从到再到四系列与部分源码解析五系列从使用了解的各种使用方案六前言我们先不讲什么语法原理先根据效果强行模拟语法使用实现一个简易版的第一步我们先用类

React系列

React系列 --- 简单模拟语法(一)
React系列 --- Jsx, 合成事件与Refs(二)
React系列 --- virtualdom diff算法实现分析(三)
React系列 --- 从Mixin到HOC再到HOOKS(四)
React系列 --- createElement, ReactElement与Component部分源码解析(五)
React系列 --- 从使用React了解Css的各种使用方案(六)

前言

我们先不讲什么语法原理,先根据API效果强行模拟语法使用,实现一个简易版的React.

render

第一步我们先用类创建一个元素返回,并且绑定点击事件,代码如下,可以正常看到一个按钮出现了.

class AddButton {
  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 };
  }

  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);
    console.log(this.dom);
    return this.dom;
  }
}

document.body.appendChild(new AddButton().render());

渲染之后看到this dom输出已经发现改变了,但是视图并没有渲染,那是因为这是结尾一次性插入,下面就渲染视图这块往下走

重新渲染

我们现在把插入数据的操作内置到class里面,新增一个方法插入新元素移除旧元素.

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(``);
    this.dom.addEventListener("click", () => this.handleAdd(), false);
    return this.dom;
  }
}

document.body.appendChild(new AddButton().render());

现在效果虽然实现,但是还是得开头手动把元素插入视图

抽取公用类

我们先将一些共有方法提取到一个多带带类

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 ``;
  }
}

还有一个问题是点击事件暂时还是耦合进Component里面,先略过不提.

ReactDom.render

大家都知道React会提供这么一个方法将组件插入一个指定元素,我们直接模拟

const ReactDom = {
  render(component, wrapper) {
    wrapper.appendChild(component._render(wrapper));
  }
};

ReactDom.render(new AddButton(), document.getElementById("root"));
Props

还有一个重要的传输数据实现如下

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 ``
  }
}

ReactDom.render(new AddButton({a:1}), document.getElementById("root"))

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106484.html

相关文章

  • React系列 --- Jsx, 合成事件与Refs(二)

    摘要:系列系列简单模拟语法一系列合成事件与二系列算法实现分析三系列从到再到四系列与部分源码解析五系列从使用了解的各种使用方案六的诞生他是的一种扩展语法。这个函数接受组件的实例或元素作为参数,以存储它们并使它们能被其他地方访问。 React系列 React系列 --- 简单模拟语法(一)React系列 --- Jsx, 合成事件与Refs(二)React系列 --- virtualdom di...

    LiuZh 评论0 收藏0
  • React系列 --- 从使用React了解Css的各种使用方案(六)

    摘要:当然这不是只限于使用或者其他打包工具的方式都能支持使用优点模块化和可重用性没有冲突显性依赖不会污染全局可以配合预处理器使用少开发单独文件写法基本一致 To define is to limit. 定义一样东西,就意味着限制了它。——王尔德 《道林·格雷的画像》 React系列 React系列 --- 简单模拟语法(一)React系列 --- Jsx, 合成事件与Refs(二)Reac...

    freecode 评论0 收藏0
  • 阿里云前端周刊 - 第 18 期

    摘要:然鹅在过去的两个月里,对的理解发生了一波三折的变化。发布自版本发布之后,一直致力于提升版本迭代速度,尽可能地通过小的更新来修复存在的问题。 推荐 1. 深入浅出 React 高阶组件 https://zhuanlan.zhihu.com/p/... 由高阶函数引申高阶组件,高阶组件是接受 React 组件作为输入,输出一个新的 React 组件的组件,本文介绍了在 React 工程中如...

    luck 评论0 收藏0
  • 阿里云前端周刊 - 第 18 期

    摘要:然鹅在过去的两个月里,对的理解发生了一波三折的变化。发布自版本发布之后,一直致力于提升版本迭代速度,尽可能地通过小的更新来修复存在的问题。 推荐 1. 深入浅出 React 高阶组件 https://zhuanlan.zhihu.com/p/... 由高阶函数引申高阶组件,高阶组件是接受 React 组件作为输入,输出一个新的 React 组件的组件,本文介绍了在 React 工程中如...

    Sanchi 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    jsbintask 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<