描述用户界面

React 是一个用于构建用户界面(UI)的 JavaScript 库,用户界面由按钮、文本和图像等小单元内容构建而成。React 帮助你把它们组合成可重用、可嵌套的 组件。从 web 端网站到移动端应用,屏幕上的所有内容都可以被分解成组件。在本章节中,你将学习如何创建、定制以及有条件地显示 React 组件。

你的第一个组件

React 应用是由被称为 组件 的独立 UI 片段构建而成。React 组件本质上是可以任意添加标签的 JavaScript 函数。组件可以小到一个按钮,也可以大到是整个页面。这是一个 Gallery 组件,用于渲染三个 Profile 组件:

function Profile() {
  return (
    <img
      src="https://i.imgur.com/MK3eW3As.jpg"
      alt="Katherine Johnson"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 你的第一个组件 以学习如何声明并使用 React 组件

阅读更多

组件的导入与导出

你可以在一个文件中声明许多组件,但文件的体积过大会变得难以浏览。为了解决这个问题,你可以在一个文件中只导出一个组件,然后再从另一个文件中导入该组件:

import Profile from './Profile.js';

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 组件的导入与导出 以学习如何切分组件。

阅读更多

使用 JSX 书写标签语言

每个 React 组件都是一个 JavaScript 函数,它可能包含一些标签,React 会将其渲染到浏览器中。React 组件使用一种叫做 JSX 的语法扩展来表示该标签。JSX 看起来很像 HTML,但它更为严格,可以显示动态信息。

如果我们把现有的 HTML 标签粘贴到 React 组件中,它并不一定能成功运行:

export default function TodoList() {
  return (
    // This doesn't quite work!
    <h1>Hedy Lamarr's Todos</h1>
    <img
      src="https://i.imgur.com/yXOvdOSs.jpg"
      alt="Hedy Lamarr"
      class="photo"
    >
    <ul>
      <li>Invent new traffic lights
      <li>Rehearse a movie scene
      <li>Improve spectrum technology
    </ul>

如果你有像这样的现有的 HTML 片段,你可以使用它进行语法转换 converter

export default function TodoList() {
  return (
    <>
      <h1>Hedy Lamarr's Todos</h1>
      <img
        src="https://i.imgur.com/yXOvdOSs.jpg"
        alt="Hedy Lamarr"
        className="photo"
      />
      <ul>
        <li>Invent new traffic lights</li>
        <li>Rehearse a movie scene</li>
        <li>Improve spectrum technology</li>
      </ul>
    </>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 使用 JSX 书写标签语言 以学习如何编写有效的 JSX。

阅读更多

在 JSX 中通过大括号使用 JavaScript

JSX 可以让你在 JavaScript 文件中编写类似 HTML 的标签语法,使渲染逻辑和内容展示维护在同一个地方。有时你会想在标签中添加一点 JavaScript 逻辑或引用一个动态属性。在这种情况下,你可以在 JSX 中使用花括号来为 JavaScript “开辟通道”:

const person = {
  name: 'Gregorio Y. Zara',
  theme: {
    backgroundColor: 'black',
    color: 'pink'
  }
};

export default function TodoList() {
  return (
    <div style={person.theme}>
      <h1>{person.name}'s Todos</h1>
      <img
        className="avatar"
        src="https://i.imgur.com/7vQD0fPs.jpg"
        alt="Gregorio Y. Zara"
      />
      <ul>
        <li>Improve the videophone</li>
        <li>Prepare aeronautics lectures</li>
        <li>Work on the alcohol-fuelled engine</li>
      </ul>
    </div>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 在 JSX 中通过大括号使用 JavaScript 以学习如何从 JSX 中访问 JavaScript 数据。

阅读更多

将 Props 传递给组件

React 组件使用 props 来进行组件之间的通讯。每个父组件都可以通过为子组件提供 props 的方式来传递信息。props 可能会让你想起 HTML 属性,但你可以通过它们传递任何 JavaScript 的值,包括对象、数组、函数、甚至是 JSX!

import { getImageUrl } from './utils.js'

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 将 Props 传递给组件 以了解如何传递并读取 props。

阅读更多

条件渲染

你的组件经常需要根据不同的条件来显示不同的东西。在 React 中,你可以使用 JavaScript 语法,如 if 语句、&&? : 操作符有条件地渲染 JSX。

在这个示例中,JavaScript 的 && 操作符将会条件渲染一个复选标签:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item
          isPacked={true}
          name="Space suit"
        />
        <Item
          isPacked={true}
          name="Helmet with a golden leaf"
        />
        <Item
          isPacked={false}
          name="Photo of Tam"
        />
      </ul>
    </section>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 条件渲染 以学习使用不同的方法对内容进行条件渲染。

阅读更多

渲染列表

通常,你需要根据数据集合来渲染多个较为类似的组件。你可以在 React 中使用 JavaScript 的 filter()map() 来实现数组的过滤和转换,将数据数组转换为组件数组。

对于数组的每个元素项,你需要指定一个 key。通常你需要使用数据库中的 ID 作为 key。即使列表发生了变化,React 也可以通过 key 来跟踪每个元素在列表中的位置。

import { people } from './data.js';
import { getImageUrl } from './utils.js';

export default function List() {
  const listItems = people.map(person =>
    <li key={person.id}>
      <img
        src={getImageUrl(person)}
        alt={person.name}
      />
      <p>
        <b>{person.name}:</b>
        {' ' + person.profession + ' '}
        known for {person.accomplishment}
      </p>
    </li>
  );
  return (
    <article>
      <h1>Scientists</h1>
      <ul>{listItems}</ul>
    </article>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 渲染列表 以学习如何渲染一个组件列表,以及如何选择一个 key

阅读更多

保持组件纯粹

有些 JavaScript 函数是 纯粹 的。纯函数的基本定义:

  • 只负责自己的任务。 它不会更改在该函数调用前就已存在的对象或变量。
  • 输入相同,输出也相同。 在输入相同的情况下,对纯函数来说应总是返回相同的结果。

严格遵循纯函数的定义编写组件,可以让代码库体量增长时,避免一些令人困惑的错误和不可预测的行为。下面是一个非纯函数组件的示例:

let guest = 0;

function Cup() {
  // Bad: changing a preexisting variable!
  guest = guest + 1;
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup />
      <Cup />
      <Cup />
    </>
  );
}

你可以通过传递一个 props 来使这个组件变得纯粹,而非修改已经存在的变量:

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup guest={1} />
      <Cup guest={2} />
      <Cup guest={3} />
    </>
  );
}

想要仔细学习这个主题的内容吗?

请参阅 保持组件纯粹 以学习如何将组件写成纯粹且可预测的函数。

阅读更多

将 UI 视为树

React 使用树形关系建模以展示组件和模块之间的关系。

React 渲染树是组件之间父子关系的表示。

一个树状图,有五个节点,每个节点代表一个组件。树状图的顶部有一个名为 Root Component 的根节点,它有两个向下延伸的箭头,分别标有 renders。两个箭头指向标有 Component A 和 Component C 的节点。Component A 有一条 renders 箭头指向标有 Component B 的节点。Component C 有一条 renders 箭头指向标有 Component D 的节点。
一个树状图,有五个节点,每个节点代表一个组件。树状图的顶部有一个名为 Root Component 的根节点,它有两个向下延伸的箭头,分别标有 renders。两个箭头指向标有 Component A 和 Component C 的节点。Component A 有一条 renders 箭头指向标有 Component B 的节点。Component C 有一条 renders 箭头指向标有 Component D 的节点。

示例的 React 渲染树

位于树顶部、靠近根组件的组件被视为顶层组件。没有子组件的组件被称为叶子组件。对组件的这种分类对于理解数据流和渲染性能非常有用。

对 JavaScript 模块之间的关系进行建模是了解应用程序的另一种有用方式。我们将其称为模块依赖树。

一个树状图,有五个节点。每个节点代表一个 JavaScript 模块。最顶部的节点标有 RootModule.js。它有三条箭头指向节点:ModuleA.js、ModuleB.js 和 ModuleC.js。每个箭头标有 imports。ModuleC.js 节点有一条 imports 箭头指向标有 ModuleD.js的节点。
一个树状图,有五个节点。每个节点代表一个 JavaScript 模块。最顶部的节点标有 RootModule.js。它有三条箭头指向节点:ModuleA.js、ModuleB.js 和 ModuleC.js。每个箭头标有 imports。ModuleC.js 节点有一条 imports 箭头指向标有 ModuleD.js的节点。

示例的模块依赖树

构建工具经常使用依赖树来捆绑客户端下载和渲染所需的所有 JavaScript 代码。对于 React 应用程序,打包大小会导致用户体验退化。了解模块依赖树有助于调试此类问题。

想要仔细学习这个主题的内容吗?

阅读 将 UI 视为树 以了解如何为 React 应用程序创建渲染和模块依赖树,以及它们如何成为有效改善用户体验和性能的心理模型。

阅读更多

接下来应该……

请访问 你的第一个组件 这个章节并开始阅读!

如若你已熟悉这些主题,可直接阅读 添加交互 一节。