实现 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


目录
相关文章
|
1天前
|
前端开发 JavaScript
React如何进行条件渲染
React如何进行条件渲染
12 0
|
1天前
|
前端开发 JavaScript 开发者
React:JSX语法入门
React:JSX语法入门
28 0
|
1天前
|
存储 前端开发 JavaScript
在回调函数中重新渲染React组件
在React中,重新渲染组件可通过`forceUpdate()`或`ReactDOM.render()`实现。方法一是使用`forceUpdate`强制无状态组件更新;方法二是通过重新创建根组件实例适用于有状态组件。这些示例基于Webpack和Babel的模块热替换配置。根据项目需求和React版本,还可以结合React-Router或Redux等库选择合适的方法。
|
1天前
|
XML 前端开发 JavaScript
react中JSX的详解
react中JSX的详解
16 2
|
1天前
|
存储 JSON 资源调度
next.js博客搭建_react-markdown渲染内容(第三步)
next.js博客搭建_react-markdown渲染内容(第三步)
9 1
|
1天前
|
数据采集 资源调度 前端开发
React的服务器端渲染:使用ReactDOMServer进行高效页面预渲染
【4月更文挑战第25天】使用ReactDOMServer,React支持服务器端渲染以实现高效预渲染。通过在Node.js环境中将React组件转化为HTML字符串,减少客户端JavaScript负载和渲染时间。优点包括更快首屏加载、改善SEO和兼容无JavaScript环境,但也会增加服务器负载、复杂性和状态管理挑战。开发者需根据项目需求平衡SSR和CSR。
|
1天前
|
前端开发 JavaScript 安全
React中的JSX:语法与原理深入解析
【4月更文挑战第25天】本文深入解析React中的JSX,一种JavaScript语法扩展,使代码更直观。JSX让开发者以HTML样式描述组件UI,但最终编译成JavaScript。通过Babel转换,JSX标签转为React.createElement()调用,创建虚拟DOM。JSX的优势在于直观性、类型安全、代码复用和工具支持,助力高效开发React组件,适应不断发展的Web应用需求。
|
1天前
|
XML 前端开发 JavaScript
【前端】深入了解React JSX语法及实例应用
【前端】深入了解React JSX语法及实例应用
18 0
|
1天前
|
前端开发 JavaScript 安全
react为什么要使用JSX
react为什么要使用JSX
25 1
|
1天前
|
前端开发 JavaScript
React渲染性能的优化
React渲染性能的优化
27 2

热门文章

最新文章