Skip to content

Latest commit

 

History

History
520 lines (300 loc) · 30.9 KB

File metadata and controls

520 lines (300 loc) · 30.9 KB

一、创建我们的应用结构

欢迎使用 React 访问渐进式网络应用!

本书将带您了解构建 React 应用的整个过程,该应用也可以作为一个渐进式 Web 应用使用。我们将不仅介绍构建这样一个应用的“方法”,还将重点介绍最佳实践以及如何度量应用以确保成功实现 PWA 功能。

渐进式 Web 应用将成为 Web 应用的未来。它们承诺提供一系列附加功能,如推送通知和可安装功能,从而将它们推向本机 iOS 或 Android 应用领域。此外,对性能的高度关注(利用尖端网络技术)意味着 PWA 可以为每个人创建快速的应用。

我们将深入讨论 PWAs 的各个方面,以及将常规 web 应用转换为渐进式应用的过程。我们还将使用 React Router 等库深入探讨 React 最佳实践。

要检查本章和未来章节的代码,您可以在查看已完成的项目 https://github.com/scottdomes/chatastrophe/ 。存储库包括每个章节的分支。访问https://github.com/scottdomes/chatastrophe/tree/chapter1 本章的最终代码。

在本章中,我们将从应用的基本结构开始。以下是我们将介绍的内容:

  • 渐进式 Web 应用的用例
  • 我们希望应用实现的基本用户故事
  • 项目结构和基本 HTML
  • 安装依赖项
  • 从 React 开始

首先,让我们为应用的旅程设置场景。

布景

你的一个朋友打电话给你,对他最新的创业点子(你知道的那个)兴奋不已。你耐心地听他的描述,但恭敬地拒绝参与其中。他很失望,但理解并承诺让你了解项目的最新细节。你低声表示同意。

几个月后,他在你的工作场所与你会面,并宣布他已经找到了一群认真的投资者,他需要你帮助他开发他向他们承诺的软件。你再次拒绝,但在讨论薪酬时,他提到了一个你无法拒绝的数字。一周后,你坐上了飞往旧金山的飞机。

在投资者面前(令你惊讶的是,他们是一个狂热的观众),你的朋友会引导你完成应用的基础知识。在流行语(“大规模互联”和“全球社区”)之间,您收集的信息足以用一句话概括应用。

“所以,这是一个聊天室……对世界上的每个人来说……同时……”

你的朋友微笑着。“是的。”

100 万陌生人在同一个房间里同时在同一个应用上交谈,你对此感到困惑,但投资者们爆发出掌声。当你向门口走去时,你的朋友再次宣布他们将如何补偿你……引用比以前更高的数字。你坐下。

问题

“问题是,”你的朋友解释说,“这个聊天室必须适合所有人。”

“全球社区,”你会意地点点头说。

“没错。每个人。即使他们在沙漠中的小屋里有糟糕的互联网。他们也应该被包括在内。”

“大规模互联,”你补充道。

“没错!所以它需要速度快、重量轻、美观、动感。”

“那么每个人都会立刻说话?那不是——”

“一个世界性的集体,是的。”

另一个问题

“另一个问题,”你的朋友说,“是我们的用户大部分都会在手机上。在路上。”

“那么你想使用 iOS 和 Android 应用?”

你的朋友挥手。“不,不。再也没有人下载应用了。特别是在发展中国家;这占用了太多的带宽。记住,全球集体。”

“因此,这是一个网络应用。”

“是的,一个网络集体。”

尽管你有最好的直觉,这个项目还是吸引了你。如何设计一个尽可能快的 web 应用?如何使其在所有网络条件下工作?除了网络之外,你如何利用本机应用的所有便利制作聊天应用?

你叹息着和他握手。“我们开始工作吧。”

开始工作

欢迎来到渐进式 Web 应用的世界。

在前面的场景中,您的朋友所描述的问题正是PWAs渐进式 Web 应用所要解决的问题。

第一个问题是,许多用户将在恶劣的网络条件下访问您的网页。他们可能是一位硅谷的技术官僚,在一家 WiFi 不好的咖啡馆里用 iPhone 上网,也可能是一位住在偏远地区的孟加拉国村民。无论哪种方式,如果你的网站没有针对他们进行优化,他们都不会留下来。

因此,应用的加载速度——其性能——成为一个可访问性问题。PWA 通过第一次快速加载来解决这个问题,之后每次加载都更快。随着本书的进展,我们将更多地讨论他们是如何做到这一点的。

其次,移动应用的安装过程对用户来说是一个障碍。这意味着您的用户需要额外致力于使用您的应用——足够多地放弃存储空间和时间,并使自己暴露于恶意和侵入性代码的可能性,而这甚至是在他们有机会尝试应用之前!

如果我们可以在没有初始投资的情况下提供本机应用体验呢?PWA 正试图弥合这一差距。在接下来的章节中,我们将再次讨论他们是如何做到这一点的,以及他们实际上有多成功。然而,这两个都是值得挑战的,解决这两个问题将为我们的应用赢得巨大的用户体验。

为什么是渐进式 Web 应用?

许多静态网页的性能都非常出色。然而,当您只需要呈现一些 HTML、CSS 和少量 JavaScript 时,在所有网络条件下都能很好地工作就不那么困难了。

当我们开始谈论 web 应用时——大型、复杂、基于 JavaScript 的工作区——性能成为一个重大挑战。我们的前端将有很多代码。如果我们的用户想要充分利用我们的应用,他们需要下载所有这些代码。当 500 KB 的 JavaScript 初始化时,我们如何确保他们不会在 10 秒钟内盯着空白的加载屏幕?

因此,我们的大多数性能增强将围绕管理 JavaScript 问题展开。这在 React 中尤其如此。

为什么要做出反应?

React正迅速成为前端 web 应用的首选解决方案。为什么?这是因为它快速、优雅,使管理大型应用变得容易。

换句话说,它使复杂性变得简单。不过,PWA 没有理由使用 React。PWA 可以是任何 web 应用或网站。

React 确实有一个主要的好处——它的组件模式,其中 UI 被分成不同的部分。正如我们将看到的,组件模式允许我们将接口分成小块代码,以缓解前面的 JavaScript 下载问题。然而,除此之外,任何前端框架对于 PWA 都同样有效。

React 的优点是它是一种构建前端应用的美丽而有趣的方式。这也是一种需要的技能。如果您将 React 的知识与 PWAs 的经验结合起来,您将在快速发展的 web 开发世界中尽可能做好未来准备。

其他名字的玫瑰

你告诉你的朋友你在 PWAs 上学到的知识并做出反应,但在你结束之前,他挥手打断了你。

“是的,是的。嘿,你觉得应该叫什么名字?”

再一次,你被一种令人不安的感觉所打动,那就是所有这些都是一个错误,你永远不应该跳上这个可疑的冒险,这个潜在的灾难。

“查塔斯多夫,”你脱口而出。

你的朋友微笑着拍拍你的背。“太棒了。好吧,去做些反应吧!”

用户故事

在我们开始构建我们的应用之前,让我们深入研究一下我们到底想要达到什么样的目标。

我们可以从用户故事开始。用户故事是对应用特定功能的描述,它是从我们的一个用户的角度构建的。

以下是Jon Dobrowolski建议的框架:

Users should be able to _____. As a user, I want to do ___ because ____. Given that I'm doing ___, I should be able to ___ in order to ___.

不过,并非所有功能都需要整个框架。让我们从一些基本示例开始:

  • 用户应该能够登录和退出应用

很简单。我不认为我们需要为这一点添加理由,因为这是一个相当基本的特性。

让我们转到更高级的内容:

  • 即使在脱机状态下,用户也应该能够查看他们的邮件
  • 作为一个用户,我希望能够在不需要互联网连接的情况下查看我的消息,因为我可能需要在移动中阅读它们
  • 考虑到我启动应用时没有互联网接入,我应该能够查看所有过去的消息

让我们介绍一下应用的一些更基本的功能。用户应该能够实时发送和接收消息。

实时功能将是我们应用的关键。聊天没有任何意义,除非它快速流畅:

  • 用户应该能够查看给定作者的所有消息
  • 作为一个用户,我希望能够查看一个给定用户发送的所有消息的列表,因为我可能需要查看他们对对话的贡献,而不受其他人消息的干扰
  • 如果我点击了一个用户的电子邮件,我会被带到一个包含他们所有信息的个人资料视图

纵断面图是您建议客户端管理主聊天室不可避免的混乱的一项特殊功能。

让我们再添加几个 PWA 特定的用户故事:

  • 当另一个用户发送消息时,用户应收到推送通知
  • 作为一名用户,我希望不断了解对话的进展情况,因为我不想错过任何重要的事情
  • 鉴于聊天室未打开或在我的屏幕上不可见,我应该会收到其他用户发送的每条消息的通知

和安装:

  • 用户应该能够在其移动设备上安装应用
  • 作为一名用户,我希望能够在不导航到浏览器中的 URL 的情况下打开应用,因为我希望轻松访问聊天室
  • 鉴于我是第一次注册聊天室,系统会提示我在设备上安装该应用

不要担心我们将如何实现这些目标;我们会在适当的时候解决这个问题。现在,让我们继续记录我们想要做的事情。

我们的客户非常注重性能,因此让我们具体说明一些特定于性能的目标:

  • 即使在不稳定的网络条件下,用户也应该能够在 5 秒内加载应用
  • 作为一名用户,我希望能够尽快与应用交互,因为我不希望被困在等待加载的过程中
  • 考虑到我使用糟糕的互联网连接打开了应用,我仍然应该在 5 秒内加载它

在 5 秒内加载对于我们的应用来说仍然有点模糊。我们将在有关性能的章节中更深入地回顾这个故事。

前面提到的用户故事涵盖了我们应用的基本功能。让我们谈谈这些要点所带来的具体挑战。

应用挑战

通过以下每一项,我鼓励您思考如何在 web 应用的上下文中解决这些问题。希望,这将使您更好地了解我们试图通过 PWAs 实现的目标,以及我们面临的困难。

瞬间加载

通过渐进式 Web 应用,我们旨在提供比典型 Web 应用更接近本机应用(从 Apple app Store、Google Play Store 或其他应用商店下载的应用)的体验。当然,本机应用的优势之一是所有相关文件都是预先下载和安装的,而每次用户访问 web 应用时,他们可能需要再次下载所有资产。

解决方案是什么?当用户第一次访问页面时,下载这些资产,然后保存它们以备将来使用(也称为缓存)。然后,当用户重新打开应用时,我们不再通过 internet 再次下载文件(慢速),而是从用户的设备检索文件(快速)。

但是,这仅适用于用户重新访问应用时。对于首次访问,我们仍然需要下载所有内容。这种情况尤其不稳定,因为当用户第一次访问 Chatastrophe 时,他们还没有按其价值出售,因此,如果加载时间过长,他们可能会(永久)离开。

我们需要确保我们的资产尽可能优化,并且我们在第一次访问时下载的内容尽可能少,这样用户就不会离开。

简言之,第一次就诊快速加载,随后每次就诊几乎立即加载。

提醒推送

没有通知的聊天应用毫无意义!我们再次尝试模拟传统上本机应用的功能——直接将通知推送到用户的设备。

这个问题比看起来更棘手。推送通知仅在应用未打开时接收(毕竟,这是关键)。那么,如果我们的 web 应用没有打开并运行,我们怎么可能运行代码来显示通知呢?

答案是使用第三方服务,该服务旨在向注册设备发送通知。因此,发送消息的设备不是接收消息通知其用户的设备,而是通知我们的通知服务,然后通知所有相关设备。

我们还需要一段持续“开启”的代码——始终运行并等待从第三方服务接收通知并显示它们。这个挑战直到最近才通过 web 技术得以解决,这也是 PWA 如此令人兴奋的原因之一。

现在,如果这个区别还没有“点击”,不用担心。稍后我们将更详细地讨论它。现在,关键是推送通知对于我们的 web 应用来说将是一个有趣的挑战。

离线访问

即使我们的用户没有连接到 internet,他们也应该能够检查过去的消息并在我们的应用中导航。

答案与前面关于即时加载的讨论是一致的。我们只需要缓存应用运行所需的一切,然后按需加载;当然,简单地说,这是关键。

移动优先设计

多年来,网络设计的流行语一直是响应迅速的——当从桌面扩展到手机大小时,网站看起来也一样好。

PWA 本质上是一种基于类固醇的响应性设计,将移动应用的设计扩展到应用的各个方面,从外观到功能。

然而,在一天结束时,我们需要确保我们的应用在每个屏幕大小上都看起来很棒。在我们已经讨论过的限制条件下,它也需要看起来很好。我们不能太依赖大背景图像或强烈的图形。我们需要一个简单美观的用户界面,为外观和性能而设计。

渐进增强

任何 React 应用的性能瓶颈都是下载和运行 JavaScript。我们的整个应用代码将包含在 JavaScript 文件中——在这些文件执行之前,我们的应用无法工作。这意味着我们的用户可能会一直盯着一个白色屏幕(没有任何功能),直到 JavaScript 准备就绪。

渐进增强是一种旨在解决该问题的技术。从本质上讲,这意味着随着应用的下载,用户的体验会逐渐改善,具体取决于用户的浏览器。换句话说,应用体验随着时间的推移(以及更多的应用下载)和用户软件的改进而改进。

拥有最现代的浏览器、最快的互联网连接和完全下载的应用的用户将获得最佳体验,但浏览器过时、连接不稳定、刚刚登录页面的用户也将获得优质体验。

这意味着我们的React.js应用需要在没有任何 JavaScript 的情况下具有一些功能。这是一个有趣的挑战。

把我们的用户体验想象成一系列的层次,从好到好,随着时间的推移,我们逐渐建立起来。

我们走吧

我希望前面的概述已经为您提供了我们试图通过此应用实现的具体想法,以及实现这些目标的障碍。有很多挑战,但是当我们处理我们的用户故事时,我们将一个接一个地处理它们,直到我们有一个快速且功能完善的渐进式 Web 应用。

通过前面提到的挑战,您可以看到总体趋势:在任何条件下都有良好的性能和用户体验。当然,这是一个值得追求的目标,也是 PWA 技术适用于任何 web 应用的确切原因;他们只是承诺给每个人带来更好的体验。

一旦我们开始构建我们的应用,我们还将看到解决这些问题仍然是一个挑战,但所有这些都可以通过 React 实现。

下一步是为应用设置所有内容,并使用 HTML 和 CSS 创建基本的文件夹结构。

我们的应用框架

第一件事。在开始构建 React 应用之前,让我们先使用基本的 HTML 和 CSS 进行设置——如果您愿意的话,这是我们应用的框架,我们将在其上堆积 React 肌肉:

  1. 打开终端并切换到要存储项目的目录。
  2. 然后,我们将使用mkdir chatastrophe创建我们的应用目录。让我们进入该文件夹,在其中创建另一个名为**public的文件夹,以及public****touch index.html的文件夹。如果您在 Windows 上,请使用type nul > index.html而不是touch**:

  1. 然后,在您选择的文本编辑器中打开整个chatastrophe文件夹。我将在本教程中使用升华文本 3。打开index.html文件,让我们编写一些 HTML!

  2. 让我们从基本的 HTML 元素开始。创建一个<html>标记,并在该标记中创建<head><body>

  3. 如果没有 hello world,这将不是一个编程教程,因此在正文中,让我们将Hello world!放在<h1>标记中。

  4. 然后,在浏览器中打开index.html

在本章末尾,我们的目标是显示与前面插图完全相同的内容,但使用 React 呈现我们的<h1>

我们为什么把我们的index.html放在公用文件夹中?嗯,我们的 HTML 是我们的用户访问我们的页面时首先下载的东西。他们将完全按照我们在这里看到的方式下载。这与我们的 React JavaScript 形成了鲜明的对比,后者在提供给客户机之前将被传输(在下一章中会有更多介绍)。我们编写的 React 代码是私有的。我们编写的 HTML 将是公开的。

当我们进入 React 世界时,这一区别会更有意义,但现在,只需知道约定是将 HTML 和静态资产放在公共文件夹中。

CSS 和资产

我们在这家初创公司的好朋友(现在被称为 Chatastrophe——你做了什么?)聘请了一位设计师为我们提供一些基本资产。其中包括聊天框的发送图标和应用的徽标。你不喜欢这种风格,但这是生活。

让我们继续从下载图像文件 https://github.com/scottdomes/chatastrophe-assets 。您可以通过单击“克隆”或“下载”按钮,然后选择“下载为 Zip”来下载它们。然后,将这些文件解压到名为assets的新文件夹中的public文件夹中(因此,所有资产文件都应位于chatastrophe/public/assets中)。

在我们继续之前,我们可以通过在index.html中对资产进行测试来确保资产看起来正常。在<h1>上方,我们放入一个img标签,src设置为/img/logo.png,ID 为test-image

<img src=”img/icon.png” id=”test-image”/>

下面是它的外观:

这更漂亮。

我们需要做的最后一件事是添加 CSS。幸运的是,我们所有的 CSS 都已经神秘地为我们准备好了,省去了设计应用样式的繁琐任务。我们所要做的就是把车停下来。

我们将其包含在我们的index.html中,并带有链接标签:

我们应该看到我们的页面立即发生了变化。背景应该是渐变,图像现在应该有轻微的脉冲动画:

成功了!这就是我们的主要资产。让我们继续讨论 HTML 的一些改进。

元标记和 favicon

我们的应用将首先是移动的,正如我们已经讨论过的。为了确保我们的 HTML 得到充分优化,让我们添加更多的标记。

首先,让我们在index.html的顶部添加一个DOCTYPE声明。这会告诉浏览器所需的文档类型。在 HTML 5(HTML 的最新版本)中,它总是如下所示:

<!DOCTYPE html>

接下来,我们需要为viewport宽度添加一个元标记。看起来是这样的:

<meta name="viewport" content="width=device-width, initial-scale=1">

这有什么用?本质上,它告诉浏览器以与其屏幕相同的宽度显示网页。因此,如果网页看起来是 960px,而我们的设备是 320px 宽,而不是缩小并显示整个页面,它会将所有内容压缩到 320px。

正如您所料,只有当您的网站响应迅速且能够适应较小的规模时,这才是一个好主意。然而,由于响应能力是我们的主要目标之一,让我们从一开始就这样做。将此标签添加到我们文档的<head>中。

还有两个标签!我们在网页上使用的字符集可以用两种不同的方式编码:UnicodeISO-8859-1。您可以查看这些编码以了解更多信息,但长话短说,我们使用的是 Unicode。让我们这样添加它,就在前一个<meta>标记的正下方:

<meta charset="utf-8">

现在,让我们添加 HTML 所使用的语言。在我们现有的<html>标签上,添加lang="en"

<html lang="en">

好的,这就是 HTML 管理的目的。我们最不需要的是一个favicon,浏览器选项卡中标题旁边显示的小图标。这包括在我们的资产包中,所以我们所要做的就是将其链接起来(就在我们的<meta>标签下面):

<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">

您的浏览器选项卡现在应如下所示:

这样,我们就完了!

接下来,我们将看看如何在项目中包括 React,以及我们需要的所有其他依赖项。

什么是 npm?

React 应用主要是 JavaScript。如果您有使用 JavaScript 的经验,您就会知道浏览器完全能够自行解析和执行 JavaScript。

在大多数基础网站中,我们以<script>标记链接到页面所需的 JavaScript,浏览器下载并运行它。

我们将在 React 应用中做类似的事情(有相当多的复杂性;更多内容请参见第 2 章,开始使用 Webpack

但是,JavaScript 不再局限于浏览器。越来越多的应用也在后端使用 JavaScript,JavaScript 在自己的环境中运行。

长话短说,JavaScript 现在无处不在,而这种扩散背后的驱动力是一个 JavaScript 运行库Node.js,它允许您在浏览器环境之外运行 JavaScript。

好吧,这很令人兴奋,但为什么这对我们的 React 项目很重要?

Node 还将包的思想引入到 JavaScript 中。软件包本质上是第三方代码库,您可以将其安装到应用中,然后在需要时随时随地导入和使用它们。即使应用不是节点应用,也可以使用包。

React 就是这样一个包。前面提到的 Webpack 是另一个。简而言之,为了构建一个复杂的 web 应用,我们不可避免地会依赖很多其他人的代码,所以我们需要软件包,我们需要节点的软件包管理器(速记**npm**来安装它们。

我们还将使用npm启动应用并执行一些基本任务,但其主要目的是管理包。

节点设置

好了,说够了。让我们继续安装 Node,它与npm捆绑在一起:

  1. 转到https://nodejs.org 下载节点最新稳定版本:

  1. 在这里,我会选择 v6.10.3,这是为大多数用户推荐的版本。
  2. 安装完成后,打开终端并运行**node -v**确认安装:

  1. 您也可以通过运行npm -v来确认npm已经包含在内。

重申一下,Node 是一个 JavaScript 运行时,用于在浏览器之外执行 JavaScript,npm是一种管理 JavaScript 代码模块的方法。在本书中,我们不会直接使用 Node,但我们会大量使用npm

npm 的黑暗面

在过去的一年中,npm因各种原因受到攻击。

  • 速度可能会很慢(只需尝试通过糟糕的 Wi-Fi 连接安装大型软件包即可)
  • 它的安装过程可以为同一项目中的不同开发人员带来不同的结果
  • 即使您以前下载过该软件包,它也无法脱机工作

为了应对这些问题,Facebook 推出了一个名为**纱线的软件包管理器。**纱线本质上是npm周围的包装物,赋予相同的基本功能和额外的一层美好。让我们继续安装它,以便我们可以使用它来管理我们的软件包!

访问https://yarnpkg.com/en/docs/install 获取安装说明。对于 macOS,请注意,您需要自制(就像 macOS 软件包的npm——到处都有软件包!),您可以在上获得该软件包 https://brew.sh/.

项目启动

我们需要做的下一件事是作为一个npm项目启动我们的应用。让我们尝试一下,然后我们将讨论为什么需要这样做:

  1. project文件夹中,在终端中,键入yarn init并按 enter 键。
  2. 它会问你一系列问题。第一个是最重要的——应用的名称。它应该只使用当前文件夹的名称(chatastrophe。如果没有,只需输入chatastrophe。从那里,只需按 enter 键跳过其余的问题,接受默认答案。如果我们计划发布我们自己的软件包,这些问题会更重要,但我们没有,所以不用担心!
  3. 如果您在完成 Thread init 后查看项目文件夹,您会注意到它添加了一个带有项目名称和版本的package.json文件。我们的package.json很重要,因为它将充当我们依赖项的列表——我们将通过yarn安装的包。

关于依赖关系的讨论已经够多了,让我们安装我们的第一个!还有什么比安装 React 更好的选择?

安装反应器

让我们从您的project文件夹中运行yarn add react@15.6.1来尝试一下。

We're installing a specific version of React (15.6.1) to ensure compatibility with other dependencies, and to ensure that there are no unexpected problems as new versions are released.

一旦安装完成,您将看到 React 添加到我们的package.json中的 dependencies 下。您还会看到yarn生成了一个node_modules文件夹和一个yarn.lock文件。

node_modules文件夹是我们所有包裹的存放处。如果你打开它,你可以看到已经有几个文件夹了。我们不仅安装了 React,而且还安装了 React 所依赖的一切—依赖依赖依赖。

正如你所想象的,node_modules文件夹可能会变得相当大。所以,我们不把它签入源代码管理。当新开发人员加入团队并下载项目文件时,他们可以基于package.json独立安装依赖项;这节省了时间和空间。

但是,我们需要确保他们获得与其他人相同的软件包,以及相同的版本;这就是yarn.lock文件的来源。

前面提到的设置确保我们可以安全地使用第三方库。我们的项目中有package.jsonyarn.locknode_modules文件夹。在继续之前,让我们确保添加 React 有效。

使用 React

让我们通过使用 React 向屏幕呈现一个简单元素来确认 React 在我们的项目中。这将是我们第一次将脚伸入 React,所以请放慢脚步,确保您理解每一步。

首先,我们需要将 React 软件包(我们刚刚安装了yarn)导入到我们的index.html中,以便在那里使用它。

为此,我们在node-modules文件夹中添加了一个<script>标记,其中包含主 React 文件的路径。此标记如下所示:

<script src="../node_modules/react/dist/react.js"></script>

将其放置在您的index.htmlbody标签底部(在结束</body>之前)。

好了,我们有反应了!让我们用它来制作一个简单的<h1>标记,就像我们用 HTML 编写的标记一样。

React 有一个名为createElement的函数用于此目的。它有三个参数:元素类型、称为 props 的东西(稍后将详细介绍)和子元素(标记中的内容)。

对我们来说,情况是这样的:

React.createElement('h1', null, 'Hello from React!')

此函数调用将创建一个如下所示的元素:

<h1>Hello from React!</h1>

为了确认它会起作用,让我们console.log把它弄出来:

<script src="../node_modules/react/dist/react.js"></script>
<script>
  console.log(React.createElement('h1', null, 'Hello from react!'))
</script>

重新加载index.html,然后右键单击或控制单击并选择 Inspect 以在 Chrome 中打开 DevTools 并切换到 Console 选项卡。在那里,我们看到了我们的元素…或者没有。我们得到的不是 HTML 输出,而是如下所示:

这不是我们可能期望的 HTML 元素,但我们可以看到 React 以其自己的方式工作。我们有一个类型字段为h1的 JavaScript 对象。让我们看看是否可以将其转换为屏幕上的实际 HTML 标记。

欢迎来到 ReactDOM

这里有一个关于 React 的秘密——它是用于创建 UI 的库,但不是用于呈现 UI 的库。它本身没有向浏览器呈现 UI 的机制。

幸运的是,React 的创建者也有一个名为ReactDOM的包,正是为了这个目的。让我们安装它,然后看看它是如何工作的。

首先我们用**yarn add react-dom@15.6.1**来安装。

然后,在index.html中以与 React 大致相同的方式要求它:

<body>
  <img src="img/icon.png" id="test-image"/>
  <h1>Hello world!</h1>
  <div id="root"></div>
  <script src="../node_modules/react/dist/react.js"></script>
 <script src="../node_modules/react-dom/dist/react-dom.js"></script>
  <script>
    console.log(React.createElement('h1', null, 'Hello from react!'));
  </script>
</body&gt;

ReactDOM 有一个名为render的函数,它接受两个参数:要呈现到屏幕上的 React 元素(嘿,我们已经有了!),以及将在其中呈现的 HTML 元素。

我们有第一个论点,但没有第二个。我们需要现有 HTML 中的一些东西,我们可以抓住并钩住它;ReactDOM 将把我们的 React 元素注入其中。

因此,在我们现有的<h1>标记下面,创建一个 ID 为root的空div

然后,在我们的ReactDOM.render函数中,我们将传入 React 元素,然后使用document.getElementById获取新的div

我们的index.html应该是这样的:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="utf-8">
    <link rel="stylesheet" href="img/app.css">
    <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
  </head>
  <body>
    <img src="img/icon.png" id="test-image"/>
    <h1>Hello world!</h1>
    <div id="root"></div>
    <script src="../node_modules/react/dist/react.js"></script>
    <script src="../node_modules/react-dom/dist/react-dom.js"></script>
    <script>
      ReactDOM.render(React.createElement('h1', null, 'Hello from react!'), 
      document.getElementById('root'));
    </script>
  </body>
</html>

重新加载页面,你应该看到屏幕中间的文本 T0!

总结

成功

在接下来的几章中,我们将深入(非常、非常深入)讨论 ReactDOM 和 React。我们将学习如何以更直观的方式创建元素,以及 React 如何使构建 UI 成为梦想。

现在,我们已经准备好了项目框架,作为未来应用的基础。干得好!

我们的下一步是完成准备的最后一个阶段,并深入了解我们最重要的依赖项之一——一个称为 Webpack 的工具。