实现 Toy-React , 实现 JSX 渲染(下)

简介: 实现 Toy-React , 实现 JSX 渲染

3. 可以看到 createElement 的第一个参数已经不再是 string ,而是我们定义的 Class 类,于是可以进行第一步改造,根据 type 进行对应的处理

function createElement(type, attributes, ...children) {
  let currentElement;
  if (typeof type === "string") {
    // 创建 dom 实例
    currentElement = document.createElement(type);
  }else {
    // 获取对应的 dom 实例
    currentElement = new type().render();
  }
  // 处理属性
  if (attributes) {
    for (const name in attributes) {
      currentElement.setAttribute(name, attributes[name]);
    }
  }
  // 处理子节点
  if (children.length) {
    for (let child of children) {
      // 处理文本节点
      if (typeof child === "string") {
        child = document.createTextNode(child);
      }
      // 往当前元素中插入子节点
      currentElement.appendChild(child);
    }
  }
  return currentElement;
}
复制代码

这样一来,我们就可以成功渲染 Class 组件

image.png

五、抽离逻辑实现 Toy-React

尽管上面我们实现了对 JSX 的渲染,但所有操作都在 main.jsx 中进行,包括 createElement 方法也是直接在该文件中声明和实现的,既然我们要实现 Toy-React , 那么我们应该要保证其在使用上要和 React 保持一致.

1. createElement 中要实现的功能有:

  • 获取或创建 dom 实例
  • 为 dom 实例设置 attribute
  • 创建文本节点
  • 为 dom 实例添加子节点
  • 返回最终的 dom 实例

2. 为了让 createElement 中所有的 type 都能拥有正常调用 DOM API 的能力,我们需要给所有的 type 定义一个通用 ElmentWrapper,同时也为文本节点定义一个对应的 TextWrapper.

3. 同样的,为了让所有的 Class 组件拥有共同的一些功能特性,我们需要实现 Component 这个类,来保证所有 Class 组件拥有统一性.

4. 在 main.jsx 中最后是通过 document.body.appendChild(JSX) 的方式,把 JSX 转换后的结果最终渲染在页面上的,因此,在这里我们要实现 render 方法去替换这种方式.

toy-react.js 最终实现如下:

// ElementWrapper
class ElementWrapper {
  constructor(type) {
    this.root = document.createElement(type);
  }
  setAttribute(name, value) {
    this.root.setAttribute(name, value);
  }
  appendChild(component) {
    this.root.appendChild(component.root);
  }
}
// TextWrapper
class TextWrapper {
  constructor(content) {
    this.root = document.createTextNode(content);
  }
}
// Component
export class Component {
  constructor() {
    this._root = null;
    this.props = {};
    this.children = [];
  }
  setAttribute(name, value) {
    this.props[name] = value;
  }
  appendChild(component) {
    this.children.push(component);
  }
  get root() {
    if (!this._root) {
      this._root = this.render().root;
    }
    return this._root;
  }
}
// createElement
export function createElement(type, attributes, ...children) {
  // 1. 获取 dom 实例
  let currentElement;
  if (typeof type === "string") {
    currentElement = new ElementWrapper(type);
  } else {
    currentElement = new type();
  }
  // 2. 处理 dom 实例属性
  if (attributes) {
    for (const name in attributes) {
      currentElement.setAttribute(name, attributes[name]);
    }
  }
  // 3. 处理子节点
  const insertChildren = (children) => {
    if (children.length) {
      for (let child of children) {
        // 处理文本节点
        if (typeof child === "string") {
          child = new TextWrapper(child);
        }
        // 当子节点拥有子节点时,递归处理
        // 即在组件中使用了 { this.children } 表达式
        if (typeof child === "object" && child instanceof Array) {
          insertChildren(child);
        } else {
          currentElement.appendChild(child);
        }
      }
    }
  };
  // 初始化调用
  insertChildren(children);
  return currentElement;
}
// render
export function render(component, parentElement) {
  parentElement.appendChild(component.root);
}
复制代码

在 main.jsx 中使用如下:

import { createElement, render, Component } from './toy-react'; 
class MyComponent extends Component {
  render() {
    return (<div id="MyComponent">
      <h1>i am MyComponent</h1>
      { this.children }
      </div>);
  }
}
const JSX = (
  <div id="jsx">
    <h1>i am Jsx</h1>
    <MyComponent>
      <h1>i am MyComponent child</h1>
    </MyComponent>
  </div>
);
render(JSX, document.querySelector("#app"));
复制代码

渲染结果

image.png


目录
相关文章
|
4月前
|
前端开发 JavaScript
React学习之——条件渲染
【10月更文挑战第16天】React 中没有像Vue中v-if这种指令。React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 if 或者条件运算符去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。
|
5月前
|
前端开发 JavaScript
学习react基础(3)_setState、state、jsx、使用ref的几种形式
本文探讨了React中this.setState和this.state的区别,以及React的核心概念,包括核心库的使用、JSX语法、类与函数组件的区别、事件处理和ref的使用。
104 3
学习react基础(3)_setState、state、jsx、使用ref的几种形式
|
4月前
|
前端开发 JavaScript 容器
React 元素渲染
10月更文挑战第7天
43 1
|
4月前
|
监控 前端开发 UED
在 React 18 中利用并发渲染提高应用性能
【10月更文挑战第12天】利用并发渲染需要综合考虑应用的特点和需求,合理运用相关特性和策略,不断进行优化和调整,以达到最佳的性能提升效果。同时,要密切关注 React 的发展和更新,以便及时利用新的技术和方法来进一步优化应用性能。你还可以结合具体的项目实践来深入理解和掌握这些方法,让应用在 React 18 的并发渲染机制下发挥出更好的性能优势。
151 59
|
3月前
|
JavaScript 前端开发 容器
React零基础入门02--JSX语法基础
React零基础入门02--JSX语法基础
React零基础入门02--JSX语法基础
|
3月前
|
XML 前端开发 JavaScript
react之了解jsx
react之了解jsx
|
4月前
|
JavaScript 前端开发 算法
前端优化之超大数组更新:深入分析Vue/React/Svelte的更新渲染策略
本文对比了 Vue、React 和 Svelte 在数组渲染方面的实现方式和优缺点,探讨了它们与直接操作 DOM 的差异及 Web Components 的实现方式。Vue 通过响应式系统自动管理数据变化,React 利用虚拟 DOM 和 `diffing` 算法优化更新,Svelte 通过编译时优化提升性能。文章还介绍了数组更新的优化策略,如使用 `key`、分片渲染、虚拟滚动等,帮助开发者在处理大型数组时提升性能。总结指出,选择合适的框架应根据项目复杂度和性能需求来决定。
|
4月前
|
XML 前端开发 JavaScript
React JSX
React 使用 JSX(一种类似 XML 的 JavaScript 语法扩展)来替代传统 JavaScript 编写 UI。JSX 使代码更简洁、执行更快且类型安全。例如,`&lt;h1&gt;Hello, world!&lt;/h1&gt;` 实际上是创建一个 React 元素,通过 `ReactDOM.render()` 渲染到 DOM。注意,JSX 中使用 `className` 替代 HTML 的 `class` 属性。
|
4月前
|
前端开发 JavaScript 算法
React 渲染优化策略
【10月更文挑战第6天】React 是一个高效的 JavaScript 库,用于构建用户界面。本文从基础概念出发,深入探讨了 React 渲染优化的常见问题及解决方法,包括不必要的渲染、大量子组件的渲染、高频事件处理和大量列表渲染等问题,并提供了代码示例,帮助开发者提升应用性能。
80 6
|
4月前
|
XML 前端开发 JavaScript
React JSX
10月更文挑战第7天
28 2