什么是 React

React是一个简单的javascript UI库,用于构建高效、快速的用户界面。它是一个轻量级库,因此很受欢迎。它遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效。它使用虚拟DOM来有效地操作DOM。它遵循从高阶组件到低阶组件的单向数据流。

前言 

 我们认为,React 是用 JavaScript 构建快速响应的大型 Web 应用程序的首选方式。它在 Facebook 和 Instagram 上表现优秀。官网地址

教你如何从 html 实现一个 react

react 的理念是在于对大型项目的快速响应,对于新版的 react 16.8 而言更是带来的全新的理念fiber去解决网页快速响应时所伴随的问题,即 CPU 的瓶颈,传统网页浏览受制于浏览器刷新率、js 执行时间过长等因素会造成页面掉帧,甚至卡顿

react 由于自身的底层设计从而规避这一问题的发生,所以 react16.8 的面世对于前端领域只办三件事:快速响应、快速响应、还是 Tmd 快速响应 !,这篇文章将会从一个 html 出发,跟随 react 的 fiber 理念,仿一个非常基础的 react

一开始的准备工作 

html

我们需要一个 html 去撑起来整个页面,支撑 react 运行,页面中添加<div></div>,之后添加一个 script 标签,因为需要使用import进行模块化构建,所以需要为 script 添加 type 为module的属性

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="root"></div>
  <script type="module" src="./index.js" ></script>
</body>

</html>

推荐安装一个 Live Server 插件,有助于我们对代码进行调试,接下来的操作也会用到

JavaScript

我们会仿写一个如下的 react,实现一个基础的操作,在 <input/> 绑定事件,将输入的值插入在 <h2/> 标签内:

...
function App() {
  return (
    <div>
      <input onInput={updateValue} value={value} />
      <h2>Hello {value}</h2>
      <hr />
    </div>
  );
}
...

教你如何从 html 实现一个 react

在 react 进行 babel 编译的时候,会将 JSX 语法转化为 React.createElement() 的形式,如上被 retuen 的代码就会被转换成

...
React.createElement(
  "div",
  null,
  React.createElement("input", {
    onInput: updateValue,
    value: value,
  }),
  React.createElement("h2", null, "Hello ", value),
  React.createElement("hr", null)
);
...

在线地址

从转换后的代码我们可以看出 React.createElement 支持多个参数:

type,节点类型 config, 节点上的属性,比如 id 和 href children, 子元素了,子元素可以有多个,类型可以是简单的文本,也可以还是 React.createElement,如果是 React.createElement,其实就是子节点了,子节点下面还可以有子节点。这样就用 React.createElement 的嵌套关系实现了 HTML 节点的树形结构。

我们可以按照 React.createElement 的形式仿写一个可以实现同样功能的 createElement 将 jsx 通过一种简单的数据结构展示出来即 虚拟DOM 这样在更新时,新旧节点的对比也可以转化为虚拟 DOM 的对比

{
  type:'节点标签',
  props:{
    props:'节点上的属性,包括事件、类...',
    children:'节点的子节点'
  }
}

这里我们可以写一个函数实现下列需求

原则是将所有的参数返回到一个对象上 children 也要放到 props 里面去,这样我们在组件里面就能通过 props.children 拿到子元素 当子组件是文本节点时,通过构造一种 type 为 TEXT_ELEMENT 的节点类型表示

/**
 * 创建虚拟 DOM 结构
 * @param {type} 标签名
 * @param {props} 属性对象
 * @param {children} 子节点
 * @return {element} 虚拟 DOM
 */
const createElement = (type, props, ...children) => ({
  type,
  props: {
    ...props,
    children: children.map(child =>
      typeof child === "object"
        ? child
        : {
            type: "TEXT_ELEMENT",
            props: {
              nodeValue: child,
              children: [],
            },
          }
    ),
  },
});

react 中 createElement 源码实现

实现 createElement 之后我们可以拿到虚拟 DOM,但是还需要 render 将代码渲染到页面,此时我们需要对 index.js 进行处理,添加输入事件,将 createElementrender 通过 import 进行引入,render 时传入被编译后的虚拟 DOM 和页面的根元素 root, 最后再进行executeRender调用,页面被渲染,在页面更新的时候再次调用executeRender进行更新渲染

import {createElement,render} from "./mini/index.js";
const updateValue = e => executeRender(e.target.value);
const executeRender = (value = "World") => {
  const element = createElement(
    "div",
    null,
    createElement("input", {
      onInput: updateValue,
      value: value,
    }),
    createElement("h2", null, "Hello ", value),
    createElement("hr", null)
  );
  render(element, document.getElementById("root"));
};

executeRender();

render 的时候做了什么

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。