likes
comments
collection
share

(一)手写 React 源码之准备阶段

作者站长头像
站长
· 阅读数 5

学习点

相关的基本概念如:虚拟 DOM、JSX 等

代码仓库:github.com/kjhuanhao/j…

React 是什么

需求:在页面上显示一个按钮,按钮显示的文字内容为:Hello, Count:0,每点击一次该按钮,count 的数字加1

JS实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #content {
      font-size: 22px;
      border: 1px solid grey;
      cursor: pointer;
      padding: 6px 10px;
      display: inline-block;
      border-radius: 10px;
    }
  </style>
</head>
<body>
  <div id="root">
    <div id="content" onclick="changeText()">Click Me, Count: 0</div>
  </div>
  <script lang="javascript">
    let count = 0;
    function changeText() {
      count++;
      document.getElementById("content").innerHTML = `Click Me, Count: ${count}`;
    }
  </script>
</body>
</html>

React实现

import { useState } from 'react';

export default function MyApp() {
  return (
    <div>
      <h1>Counters that update separately</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

初始准备

初始化一个 React 项目

初始化之后删除掉无用的代码和文件,以便我们可以更好去学习

  • index.js
import ReactDOM from 'react-dom/client';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<div>Simple React</div>);
  • index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Simple React</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

(一)手写 React 源码之准备阶段

虚拟 DOM

DOM 是 html 的编程接口,通过 DOM 的方式可以操作文档的结构、样式和内容

  1. DOM 是针对 html、xml 编程接口和编程语言无关
  2. DOM 实现相当于一个独立的程序,可以用 js、java、python 实现
  3. 而通过DOM 实现可以获取一个 DOM 对象,从而操作 DOM 对象
let element = document.getElementById('root')
let obj = {}
for (let key in element){ obj[key] = element[key]}
console.log(obj) 

可以通过代码去修改 DOM 对象,但是开销会非常大,所以引入了虚拟 DOM,虚拟 DOM 是用于描述 DOM对象的对象,在 js 中绝大部分的 DOM 对象的都是非必需的

(一)手写 React 源码之准备阶段 在 react 中直接打印一个react 对象

console.log(<div>Simple React</div>)

(一)手写 React 源码之准备阶段

总之,对比来看

  1. 没有虚拟 DOM 的情况下,直接操作一个 DOM 对象,其发生的变化需要遍历整棵 DOM 树
  2. 有虚拟 DOM 的情况下,直接操作一个 DOM 对象就是操作其虚拟 DOM,根据前后两个虚拟 DOM 之间的变化,可以计算出页面需要变化的地方

JSX 相关概念

JSX 是 JavaScript 的语法扩展,他既不是 js 也不是 html,通常我们使用 babel 来进行 jsx 的转换

(一)手写 React 源码之准备阶段

JSX 相关概念

JSX 是 JavaScript 的语法扩展

  • 新的转换形式
import ReactDOM from 'react-dom/client';

const root = ReactDOM.createRoot(document.getElementById('root'));
let element = <div>Hello</div>
root.render(element);

编译后会变成这样的 js 代码,为什么刚刚在 babel 中会有所不同

let element = /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", {
  children: "Hello"
}, void 0, false, {
  fileName: _jsxFileName,
  lineNumber: 4,
  columnNumber: 15
}, undefined);

babel编译后的,实际上是因为开发环境和生产环境的不同导致的

import { jsx as _jsx } from "react/jsx-runtime";
const element = /*#__PURE__*/_jsx("div", {
  children: "123"
});

不管是哪种方式,它们返回的都是一个虚拟 DOM 对象

  • 旧的转换形式,需要导入 React
import React from 'react';
let element = <div>Hello</div>
React.createElement("div", null, "Hello")

React 和 ReactDOM 的职责划分

  • react:组件相关核心 API 的暴露
  • react-dom:和 react 配套,将写好的组件进行渲染