第 1 章 Hello World

第 1 章 Hello World

让我们踏上使用 React 开发应用的旅程吧。在这一章里,你将学习如何设置 React 并编写你的第一个 Hello World 应用。

1.1 设置

首先需要获取一份 React 库的源代码。所幸的是,这个过程非常简单。

访问 http://reactjs.com(这个网站会重定向到 React 的官方 GitHub 页面,即 http://facebook.github.io/react/),然后点击 Download 按钮,再点击 Download Starter Kit,即可获得一份 ZIP 文件。解压该文件,并把压缩包中的目录复制到一个方便找到的地方。

例如:

mkdir ~/reactbook
mv ~/Downloads/react-0.14.7/ ~/reactbook/react

现在你的工作目录(reactbook)应该如图 1-1 所示。

{%}

图 1-1:你的 React 目录列表

现在,我们只使用其中的 ~/reactbook/react/build/react.js 文件。我们会在后续的学习中逐步介绍其他文件的使用。

需要注意的是,React 并没有强制规定任何目录结构。因此,你可以根据具体情况把 React 移动到其他目录,或者对 react.js 文件进行重命名操作。

1.2 Hello React World

我们首先在工作目录中编写一个简单的页面(~/reactbook/01.01.hello.html):

<!DOCTYPE html>
<html>
  <head>
    <title>Hello React</title>
    <meta charset="utf-8">
  </head>
  <body>
    <div id="app">
      <!--应用渲染的位置 -->
    </div>
    <script src="react/build/react.js"></script>
    <script src="react/build/react-dom.js"></script>
    <script>
      // 应用的JavaScript代码
    </script>
  </body>
</html>

 你可以在附带的代码库(https://github.com/stoyan/reactbook/)中找到本书使用的所有代码。

该文件仅有两个值得我们注意的地方:

  • 引入了 React 库及其 DOM 插件库(通过 <script src> 标签);

  • 定义了这个应用应该出现在页面上的位置((<div id="app">))。

 既可以在 React 应用中混用常规 HTML 内容以及其他 JavaScript 库,也可以在一个页面内使用多个 React 应用。只需要在 DOM 结构中给 React 指定渲染内容的位置即可。

现在我们添加一段输出 Hello world! 的代码。修改 01.01.hello.html 文件,把 JavaScript 注释替换为如下代码:

ReactDOM.render(
  React.DOM.h1(null, "Hello world!"),
  document.getElementById("app")
);

在浏览器中打开 01.01.hello.html 后,可以看到新的代码在应用中生效了(如图 1-2 所示)。

{%}

图 1-2:修改后的 Hello World 应用

恭喜,现在你完成了第一个 React 应用!

图 1-2 中的 Chrome 开发者工具显示了 React 生成的代码结构。从中可以看到,<div id="app"> 中的占位符被 React 应用生成的新内容所代替。

1.3 刚才发生了什么

你的第一个应用之所以成功运行,是因为在代码内部发生了一些有趣的事情。

首先,我们使用了 React 对象,所有可用的 API 都可通过该对象进行调用。实际上,React 在设计 API 时注重简化,所以需要记忆的方法名称并不多。

然后,我们使用了 ReactDOM 对象。这个对象只包含几个方法,其中 render() 方法是最有用的。在旧版本中,这些方法曾经属于 React 对象;但从 0.14 版本开始,它们被分离出来,目的是强调应用渲染实际上属于单独的概念。这是因为,你创建的 React 应用还可以渲染到不同的环境中,比如 HTML(浏览器 DOM)、canvas、原生的 Android 或 iOS 应用。

接下来,我们需要关注组件的概念。组件可以用于构建用户界面,并通过任何适当的方式进行组合。在实际应用中,你需要创建自定义组件,但在起步阶段,我们先学习使用 React 提供的一个包裹层,它用于包裹 HTML DOM 元素。该包裹层可通过 React.DOM 对象进行调用。在第一个例子中,我们使用了 h1 组件。它对应于 HTML 的 <h1> 元素,可以使用 React.DOM.h1() 方法进行调用。

最后,我们调用了熟悉的 document.getElementById("app") 方法访问 DOM 节点。函数调用通过该参数告诉 React 需要把应用渲染在页面的哪个部分。因此,这是连接你所熟知的 DOM 操作到 React 新大陆的一座桥梁。

 一旦跨过了从 DOM 到 React 的桥梁,你就不需要再进行 DOM 操作了,因为 React 实现了从组件到基础平台(浏览器 DOM、canvas、原生应用)的转化。你无需再关心 DOM,但这并不意味着不能操作 DOM。React 为开发者提供了选择的自由,你可以根据具体情况,随时回到 DOM 操作的怀抱当中。

理解了每行代码的作用之后,让我们回顾整段代码。刚才发生的事情是:在你选择的 DOM 节点中渲染了一个 React 组件。渲染过程从一个顶层组件开始,而顶层组件可以按需包含许多子元素(子元素中还可以嵌套子元素)。实际上,尽管这是一个简单的例子,但 h1 组件中仍然包含一个子元素,即文本 Hello world!。

1.4 React.DOM.*

现在,你知道可以通过 React.DOM 对象把各种各样的 HTML 元素当作 React 组件使用。(图 1-3 展示了如何通过浏览器控制台获取 React.DOM 对象的完整属性列表。)接下来我们将深入了解这个 API。

图 1-3:React.DOM 的属性列表

 注意 React.DOMReactDOM 的区别。前者是预定义好的 HTML 元素集合,而后者是在浏览器中渲染应用的一种途径(参考 ReactDOM.render() 方法)。

我们首先看看 React.DOM.* 方法接收的参数。回顾上述 Hello World 应用的代码:

ReactDOM.render(
  React.DOM.h1(null, "Hello world!"),
  document.getElementById("app")
);

h1() 方法的首个参数接收一个对象(在这个例子中是空对象 null),用于指定该组件的任何属性(比如 DOM 属性)。例如给组件传递 id 属性:

React.DOM.h1(
  {
    id: "my-heading",
  },
  "Hello world!"
),

上述例子生成的 HTML 结构如图 1-4 所示。

图 1-4:调用 React.DOM 生成的 HTML 代码

第二个参数(在这个例子中是 "Hello world!")定义了该组件的子元素。最简单的子元素就是上述例子中的文本(在 DOM 结构中是一个文本节点)。此外,你还可以通过传递更多的函数参数,进行子元素的组合与嵌套。比如:

React.DOM.h1(
  {id: "my-heading"},
  React.DOM.span(null, "Hello"),
  " world!"
),

再看另一个例子,这一次调用了多重嵌套的组件(结果如图 1-5 所示):

React.DOM.h1(
  {id: "my-heading"},
  React.DOM.span(null,
    React.DOM.em(null, "Hell"),
    "o"
  ),
  " world!"
),

图 1-5:React.DOM 嵌套调用生成的 HTML 结构

如你所见,当你开始嵌套组件时,使用上述写法会很快遇到大量的函数调用和圆括号。为了简化工作,你可以使用 JSX 语法。我们会在第 4 章将 JSX 作为独立的主题进行探讨;在此之前,我们暂且使用这种纯 JavaScript 语法。原因在于 JSX 会引起一些争议:人们在第一次接触 JSX 时通常会感到排斥(啊,要在 JavaScript 中插入 XML !),但随后就会发现离不开它了。为了让你初步感受一下,这里提供上述代码的 JSX 版本:

ReactDOM.render(
  <h1 id="my-heading">
    <span><em>Hell</em>o</span> world!
  </h1>,
  document.getElementById("app")
);

1.5 特殊 DOM 属性

下列几个 DOM 属性比较特殊,需要引起注意:classforstyle

classfor 不能直接在 JavaScript 中使用,因为它们都是 JavaScript 中的关键字。取而代之的属性名是 classNamehtmlFor

// 反例
// 属性不会生效
React.DOM.h1(
  {
    class: "pretty",
    for: "me",
  },
  "Hello world!"
);

// 正确例子
// 属性生效
React.DOM.h1(
  {
    className: "pretty",
    htmlFor: "me",
  },
  "Hello world!"
);

至于 style 属性,你不能像以往在 HTML 中那样使用字符串对其赋值,而需要使用 JavaScript 对象取而代之。通过避免使用字符串的方式,可以减少跨站脚本(cross-site scripting,XSS)攻击的威胁,因此这是一个广受欢迎的变化。

// 反例
// 属性不会生效
React.DOM.h1(
  {
    style: "background: black; color: white; font-family: Verdana",
  },
  "Hello world!"
);

// 正确例子
// 属性生效
React.DOM.h1(
  {
    style: {
      background: "black",
      color: "white",
      fontFamily: "Verdana",
    }
  },
  "Hello world!"
);

此外,在处理 CSS 属性时,还要注意使用 JavaScript API 的属性名。换句话说,就是使用 fontFamily 代替 font-family

1.6 React DevTools 浏览器扩展

如果你在尝试本章前面的例子时,打开过浏览器控制台,你会看到一条提示信息“Download the React DevTools for a better development experience: https://fb.me/react-devtools”。这个 URL 是通往浏览器扩展安装页的链接,该扩展可以帮助你调试 React 应用(如图 1-6 所示)。

{%}

图 1-6:浏览器扩展程序 React DevTools

虽然这个浏览器扩展在开始阶段可能派不上用场,但到了第 4 章你就会发现它的意义所在。

1.7 下一步:自定义组件

至此,你已经完成了 Hello World 应用的骨架。现在你知道如何:

  • 安装、设置并使用 React 库(仅仅需要引入两个 <script> 标签);

  • 在选定的 DOM 节点中渲染一个 React 组件(比如 ReactDOM.render(reactWhat, domWhere));

  • 使用内建组件,即那些常规 DOM 元素外的包裹层(比如 React.DOM.div(attributes, children))。

然而,React 真正的力量要在你开始使用自定义组件构建(并更新)应用界面后才能体现出来。下一章,我们将学习组件的具体操作。

目录