React超级教程,第2章:Hello React

总目录

在本章中,您将作为 React 开发人员迈出第一步。当您到达终点时,您将在计算机上运行微博应用程序的第一个版本!

安装Node.js

虽然 React 是在浏览器中运行的前端框架,但一些相关的实用程序被设计为使用 Node.js 引擎在您自己的计算机上运行。例如,创建全新 React 项目的项目在 Node 上运行。

如果您没有安装最新版本的 Node,请转到 Node.js 下载页面以获取它。我的建议是使用最新的可用 LTS(长期支持)版本。

您可以通过打开终端并运行以下命令来检查已安装的版本,以确认Node.js是否已正确安装在系统上:

node -v

创建初学者 React 项目

有很多方法可以创建新的 React 应用程序。React 文档建议您在创建全新的单页应用程序时使用“创建 React App”实用程序。

打开终端窗口,找到合适的父目录,然后输入以下命令以创建一个名为 的新 React 项目:react-microblog

npx create-react-app react-microblog

该命令附带了 Node.js,以及您可能更熟悉的节点。其目的是执行 Node.js包。的第一个参数是要执行的包,称为 。其他参数将在此包运行后传递给它。“创建 React 应用”包采用要创建的 React 项目的名称作为参数。npxnpmnpxcreate-react-app

您可能已经注意到,在运行它之前不需要安装。好处是它可以即时下载并运行请求的软件包。create-react-appnpx

让我们看一下新创建的项目。首先更改到反应微博客目录:

cd react-microblog

获取目录列表(在云硬盘和 Mac 上,在 Windows 上)以熟悉您的新项目。lsdir

根据您使用的创建 React App 的版本,项目的内容可能与我的项目内容不完全匹配,但您应该期望具有以下文件和目录:

  • README.md:一个简短的文档,其中包含有关如何使用 React 项目的说明。
  • package.json 和package-lock.json:标准的Node.js项目元数据文件,以及项目及其依赖项的说明。
  • public:在开发过程中将向 React 应用程序提供服务的目录。在此目录中,您将找到索引.html页面,该页面在浏览器中加载应用程序,一些图标文件和其他杂项静态文件。
  • src:应用程序的源代码目录。这是您将进行编码的地方。初学者应用程序附带一些用于简单演示应用程序的源文件。
  • node_modules:Node.js安装项目的所有依赖项的标准目录。
  • build:这不是在新创建的项目上显示的目录,但稍后当您创建项目的生产版本时,它将添加。
  • .git 和 .gitignore:git 存储库文件。乍一看,这并不明显,因为它们是隐藏的,但是创建 React App 也使应用程序成为本地 git 存储库。

在继续之前,您需要确保初学者项目运行良好。要启动 React 开发 Web 服务器,请运行以下命令:

npm start

此命令运行初始开发版本,并创建一个 Web 服务器,该服务器在 http://localhost:3000 URL 处为 React 应用程序提供服务。它还会在默认 Web 浏览器中打开此 URL。图 2.1 显示了您应该在浏览器中看到的内容。

应用程序启动并在浏览器中运行后,该命令将进入源代码监视循环。每当它检测到对源文件进行了更改时,它都会自动重建应用程序并将更新的代码发送到浏览器。这种自动监视和刷新应用程序非常方便,因此我建议您在处理应用程序时始终保持命令运行。npm startnpm start

安装第三方依赖项

该项目由“创建 React App”实用工具创建,其中包含一个标准的 Node.js package.json 文件,其中列出了用于该项目的所有第三方依赖项。依赖项的初始列表包括 和 库,以及一些其他相关包。reactreact-scripts

您要构建的应用程序需要更多的包,因此现在是安装它们的好时机。从项目的顶级目录运行以下命令:

npm install bootstrap react-bootstrap react-router-dom serve

所有这些软件包是什么?以下是一个简短的摘要:

  • bootstrap:网页的CSS用户界面库。
  • react-bootstrap:包的 React 组件库包装器。bootstrap
  • react-router-dom:实现客户端路由的 React 组件库。
  • serve:一个静态文件 Web 服务器,可用于运行 React 应用程序的生产版本。

在处理项目时,您将熟悉这些包。

应用程序结构

一方面,使用 Create React App 生成一个起始应用程序可以节省大量时间,但另一方面,您最终会得到一个应用程序,其中包含一些不必要的组件,这些组件需要在开始新项目之前删除。在本节中,您将了解刚刚创建的 React 应用程序的一般结构,当您使用它时,您将删除一些粗糙的内容。

在继续之前,请确保在终端窗口中运行该命令,并在应用程序上打开浏览器中的选项卡。您即将进行的一些更改将导致应用程序暂时中断,因此这是一个很好的机会,让您体验 React 开发服务器监视您的工作并通知您错误的方式。npm start

index.html文件

如果您曾经参与过其他Web开发项目,您可能知道浏览器加载的Web应用程序的核心有一个HTML文件。解析 HTML 文件后,浏览器会查找对呈现页面所需的其他资源(如图像、字体、样式表和 JavaScript 代码)的所有引用,并加载这些资源。

存储在公共目录中的索引.html是 React 应用程序的主 HTML 页面,或者更准确地说,它是一个模板,主 HTML 页面由 React 构建从中生成。

由于 React 是一个单页应用程序库,因此这是浏览器将加载的唯一页面。一旦浏览器下载了页面及其所有引用的资源,对应用程序的状态更改将严格通过 JavaScript 事件进行管理,始终在此页面的上下文中。

在编辑器中打开 public/index.html 并查看它。在页面的部分中,您将找到一些配置图标,字符集和其他重要页面元数据的样板,所有这些都由Create React App非常方便地生成。<head>

在本部分的某个地方,您将找到页面的元描述标签,搜索引擎使用它来在搜索结果中显示有关您网站的一些信息。这是由创建 React 应用程序生成的元描述标记:

    <meta
      name="description"
      content="Web site created using create-react-app"
    />

您将要做的第一个更改是将此描述更新为不太通用的内容。欢迎您发挥创造力并写下自己的描述,但这里有一个例子:

public/index.html:更新了元描述标记

    <meta
      name="description"
      content="Microblogging application featured in the React Mega-Tutorial"
    />

在元描述标签下方几行,您将找到页面标题:

    <title>React App</title>

运行应用程序的浏览器选项卡将显示 React 图标,后跟此标题。

将页面标题更改为“微博”,如下所示:

public/index.html:更新了页面标题

    <title>Microblog</title>

保存索引.html然后在浏览器中监视应用程序。保存后一两秒钟,浏览器选项卡中的标题将更新。

索引.html文件中不需要再进行任何更改,但在编辑器中关闭此文件之前,请向下滚动到 该部分。在本节中,您将找到应用程序的根元素,如下所示:<body>

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

当 React 应用程序启动时,它将在此元素中插入页面的内容。通常,您不需要与此进行交互,但是最好了解 React 应用程序在页面中的结束方式。<div>

Manifest.json File

除了index.html和图标之外,公共目录还有一个名为 manifest.json 的文件。此文件以 JSON 格式提供有关应用程序的信息。客户端设备(如智能手机和平板电脑)使用此文件中的信息,以便在用户在其桌面或主屏幕中安装(或创建应用程序的快捷方式)时提供更好的体验。

和 键设置为通用值,类似于索引页中的值。您可以分别将它们更新为“微博”和“反应微博”:short_namename

public/manifest.json:更新的应用程序元数据

  "short_name": "Microblog",
  "name": "React Microblog",

文件的其余部分定义了各种大小的图标以及应用程序的主题颜色。您可以将这些设置保留原样。

图标文件

用于桌面和移动快捷方式的图标和一些各种尺寸的较大图标都存储在公共目录中。如果您有这种倾向,则可以使用您喜欢的图标设计编辑或替换这些文件,但这可以随时完成,因此暂时保留这些文件也是可以的。

index.js文件

转到 src 目录,index.js文件是由index.html加载的主 JavaScript 文件。此文件的任务是引导 React 应用程序。

index.js中的代码具有 React 渲染引擎的入口点。此文件中的代码可能会有所不同,具体取决于您使用的 React 和 Create React App 的版本,但通常,您应该期望有一个主部分,其中包含用于呈现应用程序的调用,如下所示:

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

您可能会注意到此源文件中有一些奇怪的东西。首先,JSX 用于函数的参数中。此外,在顶部导入了扩展名为.css的文件,这在JavaScript语言方面没有多大意义。请记住,React 项目中的所有源文件在到达浏览器之前都要经过一个转换步骤,在浏览器中,JavaScript 语言的任何扩展都会被处理并转换为有效的代码。render()

导入扩展名为 .css 的文件能实现什么?此源代码转换过程的主要功能之一是生成优化的 JavaScript 和 CSS 捆绑包,然后由浏览器下载。导入 CSS 文件根本不会更改 JavaScript 源代码,但它会通知生成应将引用的 CSS 文件添加到应用程序的 CSS 捆绑包中。

该函数的目的是生成应用程序的内容,并将其应用于索引.html文件中的“根”节点。呈现函数的参数是表示整个应用程序的 JSX 树。render()

该符号是从 App.js源文件导入的。这是应用程序的顶级组件。您将很快了解有关组件的更多信息,但现在,请考虑表示表示表示整个应用程序的元素的分层集合。React 组件被认为是一个超级强大的 HTML 元素,因此它使用尖括号(如标准 HTML 元素)呈现。在查看 JSX 树时,您可以分辨出本机 HTML 元素和 React 组件之间的区别,因为前者使用小写字母,后者使用 CamelCase。AppApp

什么是包装的组件?这是 React 库的一部分组件。它不会呈现任何对页面可见的内容,但在开发过程中启用一些内部检查,以提醒您代码可能存在的问题。<React.StrictMode><App />

索引的底部.js您可能会看到对函数的调用。您不打算在此项目中使用它,但是如果您有兴趣,生成Web Vitals指标是React的可选功能,允许您分析应用程序的性能。reportWebVitals()

您只想在索引中进行一项更改.js。您还记得,之前您安装了一些第三方软件包。其中一个包是,它是一个CSS框架。若要将此库添加到项目中,必须导入其 CSS 文件。在导入索引.css文件的行的正上方插入以下 import 语句:bootstrap

src/索引.js:添加引导框架

import 'bootstrap/dist/css/bootstrap.min.css';

bootstrap.min.css索引.css之前导入的原因是,这为应用程序提供了重新定义或覆盖库附带的样式的选项。

保存文件后,您会注意到浏览器中应用程序的外观略有变化。这是因为引导样式会在呈现的页面上引入一些细微的视觉差异。

删除不必要的文件

src 目录有两个名为 logo.svg 和 App.css 的文件,应用程序不会使用它们,因此您将删除它们。

为什么这些文件是不必要的?徽标.svg文件是旋转的 React 徽标,显示在初学者应用程序中页面的中心。对于演示应用程序来说,这是一个不错的图形,但它在您自己的应用程序中没有位置。App.css文件存储顶级应用程序组件的 CSS 定义,但该项目还具有具有应用程序范围样式的索引.css文件,因此拥有两个 CSS 文件存在一些冗余。对于这个项目,我决定在索引.css文件中维护整个CSS样式集合。

由于应用程序是作为 git 存储库创建的,因此删除这些文件的首选方法是从终端窗口中使用,如下所示:git rm

git rm src/logo.svg src/App.css

删除这两个文件后,该过程将立即感到不安,并在终端和浏览器上喷出一些错误消息。这是因为 App.js源文件引用了现在已消失的两个文件。npm start

尽管有错误,将继续监视您的文件并等待您修复错误以重新启动应用程序。npm start

基本反应应用程序

src 目录中的 App.js 文件当前已损坏,因为它引用的文件在项目中不再存在。在本节中,您将用不需要任何外部文件的更简单的基本应用程序替换此文件中的代码。

打开 src/App.js您喜欢的编辑器或 IDE 中,删除其所有内容并将其替换为以下代码:

src/应用程序.js:基本应用程序组件

export default function App() {
  return (
    <h1>Microblog</h1>
  );
}

一旦您保存了新版本的 App.js,应用程序将自动重新加载到您的浏览器中,并在页面的左上角显示标题,如图 2.2 所示。<h1>

在 React 中,组件可以编写为类或函数。基于函数的组件更新,使用更简洁的语法,因此您将学习到这些组件。功能组件是在 React 16.8 中引入的,它与该版本中的另一个重要功能(称为 hooks)相关联。您将在以后的章节中学习钩子。

您现在知道一个 React 组件是作为一个 JavaScript 函数实现的。组件的名称是函数的名称,在本例中为 。组件名称必须以大写字母开头,并且通常以驼峰大小写形式书写。App

应用程序的顶级组件通常被赋予名称,但这只是一个约定,而不是规则。需要导出组件函数,以便可以从其他文件导入和使用它们。因此,组件函数始终使用 定义。Appexport default function ...

为了使源代码井井有条,组件将写入同名的源文件中,例如,该组件将写入名为 App.js 的源文件中。文件。App

现在来看看最重要的问题。组件函数应该做什么?在最简单的形式中,组件必须将自身的表示形式作为 HTML 元素树返回。因此,该函数被称为组件的渲染函数。上面的组件将自身呈现为包含应用程序名称的元素。当应用程序在浏览器中运行时,此元素将作为应用程序的索引.html文件中定义的根元素的子元素插入。App<h1><h1><div>

请注意将函数返回的 JSX 括起来的括号。由于 JavaScript 中存在奇怪且有些不可预测的分号规则,因此左括号需要与关键字位于同一行中,以防止 JavaScript 编译器在该行上插入虚拟分号。左括号告诉编译器表达式在下一行继续。return

动态渲染

呈现组件函数返回的 HTML 块很好,但对于您可能想要构建的绝大多数应用程序来说是不够的。大多数应用程序需要的一个关键功能是能够呈现动态内容。例如,您要构建的微博应用程序需要呈现事先未知的博客文章,并且将从后端服务中检索。

JSX 语法可以使用模板表达式进行扩展,这使得呈现存储在变量中的内容可以是单个值或列表,甚至可以定义条件呈现规则。

渲染变量

JSX 定义可以包含 JavaScript 表达式,这些表达式位于大括号内。例如,如果变量设置为字符串,则 JSX 表达式将呈现到页面。这不仅适用于文本,也适用于元素的属性,因此,例如,将呈现引用变量中存储的URL的图像。name'susan'<h1>Hello, {name}!</h1><h1>Hello, susan!</h1><img src={image_url} />image_url

此应用程序将呈现博客文章,但这些将从后端获取,但在此早期阶段,这些内容都不可用。为了避免遇到太多需要解决的问题,一种有用的技术是模拟应用程序中尚未准备好的部分。

鉴于还没有后端,让我们创建一个可以呈现到页面的模拟博客文章。将 App.js 中的代码替换为以下内容:

src/App.js:呈现博客文章

export default function App() {
  const post = {
    id: 1,
    text: 'Hello, world!',
    timestamp: 'a minute ago',
    author: {
      username: 'susan',
    },
  }

  return (
    <>
      <h1>Microblog</h1>
      <p>
        <b>{post.author.username}</b> &mdash; {post.timestamp}
        <br />
        {post.text}
      </p>
    </>
  );
}

在函数开头定义的常量是一个伪造的博客文章,可用于实现将帖子呈现到页面的代码,而不必首先实现与后端的连接,这是一项更复杂的任务。postApp()

该语句呈现与以前相同的元素,后跟一个元素,其中包含作者的用户名、时间戳和博客文章的文本,并且具有最少的 HTML 格式。直接包含在 JSX 块中的文本将逐字呈现到页面,而内部的文本将计算为 JavaScript 表达式,结果是呈现到页面的内容。return<h1><p>{ }

在此代码的先前版本中,返回了单个元素,但在此版本中也返回了一个元素。React 要求组件返回的渲染树是一个适当的树,只有一个顶级节点。添加父元素很容易,但这会在页面中呈现不必要的元素。使用空标记,效率更高,因为这些标记不会生成任何渲染输出。这些标签创建一个片段,该片段是一个不可见的父级,允许将多个节点分组到单个树中。<h1><p><div><></>

如果您习惯于经常看到在 HTML 页面中插入换行符,则表示法也可能看起来很奇怪。JSX 需要严格的 XML 语法,因此必须正确关闭所有元素。<br /><br>

图 2.3 显示了博客文章在浏览器上的外观。

呈现元素列表

上一节中演示的技术可以与分配了简单值或对象的变量或常量一起使用。但是,如果需要渲染数组,会发生什么情况呢?

当大括号内的表达式是数组时,React 会一个接一个地输出数组的元素。请考虑以下示例:

export default function RenderArray() {
  const data = ['one', 'two', 'three'];

  return (
    <>{data}</>
  );
}

此组件的输出将是 ,这不是很有用,因为项目之间没有分隔,也无法为数组的每个元素添加HTML标记。onetwothree

实现此目的的方法是使用类的方法将每个元素转换为所需的 JSX 表达式。该方法将函数作为参数。对于数组中的每个元素调用此函数一次,元素是其唯一的参数。所有这些调用的返回值都作为新数组收集并返回,这将成为组件的呈现输出。map()Arraymap()map()

要将上述列表呈现为 HTML 无序列表,可以按如下方式重写组件:

export default function RenderArray() {
  const data = ['one', 'two', 'three'];

  return (
    <ul>
      {data.map(element => {
        return <li>{element}</li>
      })}
    </ul>
  );
}

如果您不熟悉该方法,则最后一个示例中的内部语句可能看起来很奇怪。请记住,将函数作为其参数,因此此内部函数将值返回给 ,这是内部函数的调用方。Array.map()returnmap()returnmap()

使用该方法,组件的输出将变为正确的 HTML 列表:map()

<ul><li>one</li><li>two</li><li>three</li></ul>

这种技术可以应用于微博。在上一节中,应用程序呈现了单个帖子。这可以扩展到处理帖子列表。将 src/应用程序.js中的代码替换为以下内容:

src/App.js:呈现博客文章列表

export default function App() {
  const posts = [
    {
      id: 1,
      text: 'Hello, world!',
      timestamp: 'a minute ago',
      author: {
        username: 'susan',
      },
    },
    {
      id: 2,
      text: 'Second post',
      timestamp: 'an hour ago',
      author: {
        username: 'john',
      },
    },
  ];

  return (
    <>
      <h1>Microblog</h1>
      {posts.map(post => {
        return (
          <p>
            <b>{post.author.username}</b> &mdash; {post.timestamp}
            <br />
            {post.text}
          </p>
        );
      })}
    </>
  );
}

You can see how the list of posts looks in the browser in Figure 2.4.

This looks great, but there is a hidden problem. If you look at the browser’s debugging console, you will see a warning message.

Warning: Each child in a list should have a unique "key" prop.

Check the render method of `App`.

React has a performance optimization that triggers when a list that is rendered by a component changes. The goal is to update lists efficiently, by only updating the elements that were added, removed or changed. To be able to determine which elements of a list need to be updated, React requires each list element to be given a unique attribute. When all elements have a key, React can compare the current and new versions of the list and determine which elements are new, removed or updated. More importantly, it allows React to know which of the elements have not changed at all, so it can optimize the render process by reusing those items from the previous page update.key

When running in development mode, React triggers this warning when it finds a list that is rendered without keys. To remove the warning, a attribute needs to added to the top-level JSX node rendered for each element. Depending on the elements, you will need to find a unique value that can serve as identifier. Objects that are retrieved from a server back end often have an attribute that works perfectly as keys.keyid

Below is the posts loop, modified to use the attributes defined in the fake blog posts as keys.id

src/App.js: Render a list of blog posts with unique keys

      {posts.map(post => {
        return (
          <p key={post.id}>
            ...  // <-- no changes to the post JSX
          </p>
        );
      })}

Conditional Rendering

The last templating trick you are going to learn gives the React application the ability to render parts of the JSX tree only when certain condition is true.

Revisiting the example component from the previous section, see how it can be extended to show a message when the array has no elements to render:RenderArray

export default function RenderArray() {
  const data = [];

  return (
    <>
      <ul>{data.map(element => <li>{element}</li>)}</ul>
      {data.length === 0 &&
        <p>There is nothing to show here.</p>
      }
    </>
  );
}

Here the “and” operator is used to create an expression that will only include the JSX contents on the right side of the if the condition on its left is true.&&

The above example is not perfect, because when the list is empty an empty element is rendered to the page before the error message. The operator maps nicely to an if-then construct, but in this situation it would be ideal to be able to use an if-then-else, which can be implemented similarly, but using the ternary conditional operator ().<ul>&&?:

export default function RenderArray() {
  const data = [];

  return (
    <>
      {data.length === 0 ?
        <p>There is nothing to show here.</p>
      :
        <ul>{data.map(element => <li>{element}</li>)}</ul>
      }
    </>
  );
}

同样的想法可以在微博应用程序中实现。将 src/App.js的内容替换为以下代码。

src/App.js:呈现带有空警告的博客文章列表

export default function App() {
  const posts = [
    {
      id: 1,
      text: 'Hello, world!',
      timestamp: 'a minute ago',
      author: {
        username: 'susan',
      },
    },
    {
      id: 2,
      text: 'Second post',
      timestamp: 'an hour ago',
      author: {
        username: 'john',
      },
    },
  ];

  return (
    <>
      <h1>Microblog</h1>
      {posts.length === 0 ?
        <p>There are no blog posts.</p>
      :
        posts.map(post => {
          return (
            <p key={post.id}>
              <b>{post.author.username}</b> &mdash; {post.timestamp}
              <br />
              {post.text}
            </p>
          );
        })
      }
    </>
  );
}

使用此版本的应用程序,您可以注释掉常量并在其位置放置一个空数组,并且页面将自动更改为在“else”部分中显示消息,如图 2.5 所示。posts

确认条件逻辑正常工作后,请记住还原虚假的博客文章。

本章小结

  • 要轻松启动新的 React 项目,请使用创建 React 应用程序 (CRA)。
  • 在开始编写应用程序代码之前,请删除 CRA 添加的残骸。
  • React 组件是一个 JavaScript 函数,用于呈现 JSX 树并返回它。
  • 在 JSX 中插入 JavaScript 表达式,方法是将它们括在大括号中。
  • 使用 呈现元素列表,并包含每个元素具有唯一值的属性。map()key
  • 添加具有(if-then)和(if-then-else)运算符的条件呈现表达式。&&?: