My App

你好React

你好React

让我们从一个“hello world”的 React 应用程序开始,使用纯 JavaScript:

<html>
    <body>
      <div id="root"></div>
    </body>
</html>

我们从两个文件开始:一个 index.html 文件,包含一个基本的 HTML 文档,以及一个 index.js 文件,包含一个最小的 React 应用程序。

当我们运行这段代码时,我们得到了一个展示文本“Hello World!”的段落。

这里有很多要探讨的内容。我们将逐节进行。如果你愿意的话,我鼓励你花几分钟来仔细研究这个例子。看看你能通过一点侦探工作发现什么?!

1. 导入依赖项

import React from "react";
import { createRoot } from "react-dom/client";

文件的顶部有两个导入语句,使用本地 JavaScript 模块系统。我们正在从 react 依赖项中导入核心 React 库,以及从 react-dom 中导入 createRoot 函数。

如果你在想为什么有两个独立的包,那是因为 React 本身是“平台无关”的。我们有核心 react 包,然后有不同的平台专用渲染器:

  • react-dom 使用于Web
  • react-native 适用于移动端(iOS / Android)或桌面端(Windows / macOS)应用程序
  • react-three-fiber 用于使用 WebGL 和 Three.js 制作 3D 场景

每个平台都有自己的“原始组件”,这是我们用来创建用户界面的内置元素集合。在网页上,原始组件是像 <div> 、 <p> 和 <button> 这样的 HTML 元素。相比之下,React Native 没有 div,而是有 Text 、 View 和 Pressable 。当使用 react-three-fiber 时,情况变得更加复杂,原始组件是灯光、几何体、材质和相机等东西。 .

所有这些平台将使用相同的核心 React 框架,该框架来自 react 包。但是,当涉及到将所有业务逻辑转化为用户界面时,我们需要适合我们平台的正确绑定。

这实际上是一件很棒的事情,因为这意味着你在学习 React 时所掌握的技能也可以用于构建移动应用程序或 3D 界面,如果这正是你的兴趣或职业发展的方向!

“DOM”到底是什么?

DOM 是构成实时网站/ web 应用程序的活的、呼吸的结构。当我们访问一个网站时,浏览器将静态 HTML 转换为 DOM。

用一个类比来说:HTML 是特定汽车的蓝图,而 DOM 就是那辆在城市里穿行的汽车。

这是另一种看待它的方法:

  • 当你右键点击并选择“查看源代码”时,你查看的是 HTML,一个描述将要构建内容的静态文档。
  • 当你右键单击并“检查元素”以打开元素面板时,你正在与 DOM 互动。你可以更改属性并观察 UI 随之更新。

当我们使用像 React 这样的工具时,它通过 JavaScript 与 DOM 进行交互。它将根据需要创建、更新和删除 DOM 元素。

如果你想知道,DOM 代表文档对象模型(Document Object Model)。

2. 创建一个 React 元素

接下来在我们的微型应用中,我们有以下代码:

const element = React.createElement("p", { id: "hello" }, "Hello World!");

React.createElement 是一个接受 3 个或更多参数的函数:

  1. 要创建的元素类型。
  2. 我们希望这个元素具有的属性。
  3. 元素的内容。如果元素应该是空的,我们可以省略这一部分。

该函数返回一个“React 元素”。React 元素是普通的 JavaScript 对象。如果我们用 console.log(element) 检查它,我们会看到类似这样的东西:

{
  "type": "p",
  "key": null,
  "ref": null,
  "props": {
    "id": "hello",
    "children": "Hello World!"
  },
  "_owner": null,
  "_store": { "validated": false }
}

这个 JavaScript 对象是一个假设的段落标签的描述,ID 为 hello ,包含文本 "Hello World!" 。这些信息将用于构建我们在浏览器中可以看到的实际段落。

在本课程的后面,我们将学习 key 和 ref 。最后两个属性 _owner 和 _store 是供 React 内部使用的,可以安全地忽略*

DOM 层次结构

DOM 像树一样组织。就像家谱一样,单个元素可以有父母、祖父母、兄弟姐妹和孩子。

例如,考虑这个文件:

<html>
  <body>
    <main>
      <p>
        <strong>Warning:</strong>
        objects in mirror are closer than they appear.
      </p>
    </main>
    <footer>© 2022 Acme Inc.</footer>
  </body>
</html>

<main> 元素:

  • 以 <body> 作为其父级。
  • 只有一个子元素,即 <p> 元素。
  • 有唯一的兄弟姐妹<footer>。

这种层次结构是网络的重要组成部分。我们在 CSS 中引用它,当编写选择器时如下所示:

p:first-child {
  /*
    Apply styles to the paragraph if it's the
    first child within its parent container.
  */
}

React 同样采用了这种模型。正如我们所见,React 元素可以指定“子元素”。我们使用相同的语言,因为 React 元素的结构与 DOM 元素的结构一样形成层次关系。

3. 呈现应用程序

我们已经到达了最后几行代码:

const container = document.querySelector("#root");
const root = createRoot(container);
root.render(element);

document.querySelector 是一个有用的函数,可以让我们捕获对现有 DOM 元素的引用。

这在这种情况下起作用是因为我们的 index.html 文件包含以下元素:

<div id="root"></div>

这个元素将是我们应用程序的容器。当我们渲染我们的 React 应用程序时,它将在这个容器中创建并附加新的 DOM 元素。

使用 react-dom 的 createRoot 函数,我们指定该元素应该是我们应用程序的根。最后,使用 root.render(element) 渲染应用程序。

您可以将 render 函数视为一个将 React 元素转换为 DOM 节点的机器。在这种情况下,我们的 React 元素描述了一个段落标签,带有 ID 和一些文本。 render 将把该描述转换为以下 DOM 结构:

<p id="hello">Hello World!</p>

创建了那个 DOM 元素后,它会将其添加到指定的根节点的页面中。实质上,这段代码使用基于 JavaScript 的某些 HTML 描述,并利用它生成实际的 DOM 节点。

这可能看起来是创建段落的一种非常复杂的方法!但是,正如我们在本课程中将要学习的,真正的魔法发生在变化的时候。✨

这最近发生了变化!

如果您读过其他 React 教程,您可能见过类似这样的内容:

import ReactDOM from "react-dom";
 
ReactDOM.render(element, container);

这是在版本 17 及之前如何渲染 React 应用程序的。在版本 18 中(于 2022 年 3 月发布),API 更改为上面显示的 createRoot 和 render 组合。

在本课程的某些视频中,你会看到这个 API 的片段,这些片段是在我将 React 升级到最新版本之前录制的。

<html>
    <body>
      <div id="root"></div>
    </body>
</html>

构建系统

在我们这一课中看到的游乐场有点奇怪:没有 script 标签!

<html>
  <body>
    <div id="root"></div>
  </body>
</html>

当我们没有 <script src="/index.js"></script> 时,我们的代码究竟是如何运行的?

关于 React 需要知道的事情是,它是在一个构建系统中使用的。我们处理的文件是这个系统的输入。

我们可以通过检查“结果(Result)” <iframe> 中的 HTML 来亲身体验这一点:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>Sandbox - Josh’s Course Platform</title>
    <link rel="manifest" href="/manifest.json" />
    <link rel="shortcut icon" href="/favicon.ico" />
    <link rel="mask-icon" href="/csb-ios.svg" color="#fff" />
    <script
      src="/static/browserfs12/browserfs.min.js"
      type="text/javascript"
    ></script>
    <script>
      (window.process = BrowserFS.BFSRequire("process")),
        (window.Buffer = BrowserFS.BFSRequire("buffer").Buffer);
    </script>
    <link href="/static/js/babel.7.12.12.min.js" rel="prefetch" as="script" />
    <script charset="utf-8" src="/static/js/2.61b71a6f1.chunk.js"></script>
    <script charset="utf-8" src="/static/js/6.147d49776.chunk.js"></script>
  </head>
  <body>
    <div id="root">
      <p id="hello">Hello World!</p>
    </div>
  </body>
</html>

index.js 文件以及依赖项(React、React DOM)被打包到像 2.61b71a6f1.chunk.js 这样的神秘命名文件中,并且一个 <script> 标签被动态注入到 HTML 中。

我并不指望你理解所有这些标记是什么,或者它为什么存在。现在要知道的重要事情是,有一个活跃的过程可以转换我们编写的文件。

如果你没有使用过其他 JS 框架,这可能对你来说显得过于复杂。我们为什么不能像在使用 jQuery 和其他库时那样,使用 <script> 标签自己添加代码呢?

这有几个原因:

  • 正如我们将要了解的,JSX 需要被编译成 JS
  • 它使生活质量得以改善,例如能够使用最新的 JavaScript 特性
  • 这对良好的性能是必要的,因为 React 应用程序通常有数百个甚至数千个需要捆绑在一起的 JS 文件。

我们将在“行业工具(后续章节)”参考模块中更多地了解构建系统。

On this page