你的第一个组件

组件是 React 的核心概念之一。它们是你构建用户界面 (UI) 的基础,这使它们成为你开始 React 之旅的完美场所!

¥Components are one of the core concepts of React. They are the foundation upon which you build user interfaces (UI), which makes them the perfect place to start your React journey!

你将学习到

  • 什么是组件

    ¥What a component is

  • 组件在 React 应用中扮演什么角色

    ¥What role components play in a React application

  • 如何编写你的第一个 React 组件

    ¥How to write your first React component

组件:用户界面构建块

¥Components: UI building blocks

在 Web 上,HTML 允许我们使用其内置的标记集(如 <h1><li>)创建丰富的结构化文档:

¥On the Web, HTML lets us create rich structured documents with its built-in set of tags like <h1> and <li>:

<article>
<h1>My First Component</h1>
<ol>
<li>Components: UI Building Blocks</li>
<li>Defining a Component</li>
<li>Using a Component</li>
</ol>
</article>

此标记表示这篇文章 <article>、它的标题 <h1> 和一个(缩写的)目录作为有序列表 <ol>。像这样的标记,与用于样式的 CSS 和用于交互性的 JavaScript 相结合,存在于每个侧边栏、头像、模式、下拉菜单(你在 Web 上看到的每一个 UI 部分)的背后。

¥This markup represents this article <article>, its heading <h1>, and an (abbreviated) table of contents as an ordered list <ol>. Markup like this, combined with CSS for style, and JavaScript for interactivity, lies behind every sidebar, avatar, modal, dropdown—every piece of UI you see on the Web.

React 允许你将标记、CSS 和 JavaScript 组合到应用的自定义 “组件”、可重用 UI 元素中。你在上面看到的目录代码可以变成可以在每个页面上渲染的 <TableOfContents /> 组件。在底层,它仍然使用相同的 HTML 标签,如 <article><h1> 等。

¥React lets you combine your markup, CSS, and JavaScript into custom “components”, reusable UI elements for your app. The table of contents code you saw above could be turned into a <TableOfContents /> component you could render on every page. Under the hood, it still uses the same HTML tags like <article>, <h1>, etc.

就像使用 HTML 标签一样,你可以组合、排序和嵌套组件来设计整个页面。例如,你正在阅读的文档页面是由 React 组件组成的:

¥Just like with HTML tags, you can compose, order and nest components to design whole pages. For example, the documentation page you’re reading is made out of React components:

<PageLayout>
<NavigationHeader>
<SearchBar />
<Link to="/docs">Docs</Link>
</NavigationHeader>
<Sidebar />
<PageContent>
<TableOfContents />
<DocumentationText />
</PageContent>
</PageLayout>

随着项目的发展,你会注意到你的许多设计都可以通过重用你已经编写的组件来组合,从而加快你的开发速度。我们上面的目录可以添加到任何带有 <TableOfContents /> 的屏幕!你甚至可以使用 React 开源社区共享的数千个组件(如 Chakra UIMaterial UI)快速启动你的项目。

¥As your project grows, you will notice that many of your designs can be composed by reusing components you already wrote, speeding up your development. Our table of contents above could be added to any screen with <TableOfContents />! You can even jumpstart your project with the thousands of components shared by the React open source community like Chakra UI and Material UI.

定义组件

¥Defining a component

传统上,在创建网页时,Web 开发者标记他们的内容,然后通过添加一些 JavaScript 来添加交互。当交互在网络上是一个不错的选择时,这很有效。现在许多站点和所有应用都希望它。React 将交互性放在首位,同时仍然使用相同的技术:React 组件是一个 JavaScript 函数,你可以在其中添加标记。这是它的样子(你可以编辑下面的示例):

¥Traditionally when creating web pages, web developers marked up their content and then added interaction by sprinkling on some JavaScript. This worked great when interaction was a nice-to-have on the web. Now it is expected for many sites and all apps. React puts interactivity first while still using the same technology: a React component is a JavaScript function that you can sprinkle with markup. Here’s what that looks like (you can edit the example below):

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

以下是构建组件的方法:

¥And here’s how to build a component:

步骤 1:导出组件

¥Step 1: Export the component

export default 前缀是 标准的 JavaScript 语法(不特定于 React)。它允许你在文件中标记主要函数,以便你以后可以从其他文件导入它。(更多关于 导入和导出组件 中的导入!)

¥The export default prefix is a standard JavaScript syntax (not specific to React). It lets you mark the main function in a file so that you can later import it from other files. (More on importing in Importing and Exporting Components!)

步骤 2:定义函数

¥Step 2: Define the function

使用 function Profile() { },你可以定义一个名为 Profile 的 JavaScript 函数。

¥With function Profile() { } you define a JavaScript function with the name Profile.

易犯错误

React 组件是常规的 JavaScript 函数,但它们的名称必须以大写字母开头,否则它们将无法工作!

¥React components are regular JavaScript functions, but their names must start with a capital letter or they won’t work!

步骤 3:添加标记

¥Step 3: Add markup

该组件返回一个带有 srcalt 属性的 <img /> 标签。<img /> 写得像 HTML,但它实际上是 JavaScript!这种语法称为 JSX,它允许你在 JavaScript 中嵌入标记。

¥The component returns an <img /> tag with src and alt attributes. <img /> is written like HTML, but it is actually JavaScript under the hood! This syntax is called JSX, and it lets you embed markup inside JavaScript.

返回语句可以全部写在一行中,就像在这个组件中一样:

¥Return statements can be written all on one line, as in this component:

return <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />;

但是,如果你的标记并非都与 return 关键字位于同一行,则必须将其括在一对括号中:

¥But if your markup isn’t all on the same line as the return keyword, you must wrap it in a pair of parentheses:

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

易犯错误

没有括号,return 之后行中的任何代码 将被忽略

¥Without parentheses, any code on the lines after return will be ignored!

使用组件

¥Using a component

现在你已经定义了 Profile 组件,你可以将它嵌套在其他组件中。例如,你可以导出一个使用多个 Profile 组件的 Gallery 组件:

¥Now that you’ve defined your Profile component, you can nest it inside other components. For example, you can export a Gallery component that uses multiple Profile components:

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>
  );
}

浏览器看到的

¥What the browser sees

注意外壳的区别:

¥Notice the difference in casing:

  • <section> 是小写的,所以 React 知道我们指的是一个 HTML 标签。

    ¥<section> is lowercase, so React knows we refer to an HTML tag.

  • <Profile /> 以大写字母 P 开头,因此 React 知道我们要使用名为 Profile 的组件。

    ¥<Profile /> starts with a capital P, so React knows that we want to use our component called Profile.

Profile 包含更多 HTML:<img />。最后,这是浏览器看到的:

¥And Profile contains even more HTML: <img />. In the end, this is what the browser sees:

<section>
<h1>Amazing scientists</h1>
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</section>

嵌套和组织组件

¥Nesting and organizing components

组件是常规的 JavaScript 函数,因此你可以将多个组件保存在同一个文件中。当组件相对较小或彼此紧密相关时,这很方便。如果此文件变得拥挤,你始终可以将 Profile 移至单独的文件。你很快就会在 关于导入的页面 上学习如何执行此操作。

¥Components are regular JavaScript functions, so you can keep multiple components in the same file. This is convenient when components are relatively small or tightly related to each other. If this file gets crowded, you can always move Profile to a separate file. You will learn how to do this shortly on the page about imports.

因为 Profile 组件在 Gallery 内部渲染(甚至多次!),我们可以说 Gallery 是父组件,将每个 Profile 渲染为 “子级”。这是 React 魔力的一部分:你可以定义一个组件一次,然后在任意多处多次使用它。

¥Because the Profile components are rendered inside Gallery—even several times!—we can say that Gallery is a parent component, rendering each Profile as a “child”. This is part of the magic of React: you can define a component once, and then use it in as many places and as many times as you like.

易犯错误

组件可以渲染其他组件,但绝对不能嵌套它们的定义:

¥Components can render other components, but you must never nest their definitions:

export default function Gallery() {
// 🔴 Never define a component inside another component!
function Profile() {
// ...
}
// ...
}

上面的代码片段是 非常慢并且会导致错误。改为在顶层定义每个组件:

¥The snippet above is very slow and causes bugs. Instead, define every component at the top level:

export default function Gallery() {
// ...
}

// ✅ Declare components at the top level
function Profile() {
// ...
}

当子组件需要来自父级的一些数据时,通过属性传递 而不是嵌套定义。

¥When a child component needs some data from a parent, pass it by props instead of nesting definitions.

深入研究

组件一直向下

¥Components all the way down

你的 React 应用从 “根” 组件开始。通常,它会在你开始一个新项目时自动创建。例如,如果你使用 CodeSandbox 或使用框架 Next.js,则根组件在 pages/index.js 中定义。在这些示例中,你一直在导出根组件。

¥Your React application begins at a “root” component. Usually, it is created automatically when you start a new project. For example, if you use CodeSandbox or if you use the framework Next.js, the root component is defined in pages/index.js. In these examples, you’ve been exporting root components.

大多数 React 应用一直使用组件。这意味着你不仅可以将组件用于可重用的部分(如按钮),还可以用于较大的部分(如侧边栏、列表)以及最终的完整页面!组件是组织 UI 代码和标记的便捷方式,即使其中一些只使用一次。

¥Most React apps use components all the way down. This means that you won’t only use components for reusable pieces like buttons, but also for larger pieces like sidebars, lists, and ultimately, complete pages! Components are a handy way to organize UI code and markup, even if some of them are only used once.

基于 React 的框架 更进一步。它们不是使用空的 HTML 文件并让 React “接管” 使用 JavaScript 管理页面,而是从你的 React 组件自动生成 HTML。这允许你的应用在加载 JavaScript 代码之前显示一些内容。

¥React-based frameworks take this a step further. Instead of using an empty HTML file and letting React “take over” managing the page with JavaScript, they also generate the HTML automatically from your React components. This allows your app to show some content before the JavaScript code loads.

尽管如此,许多网站只使用 React 来 向现有 HTML 页面添加交互性。它们有许多根组件,而不是整个页面的单个组件。你可以根据需要使用尽可能多或尽可能少的 React。

¥Still, many websites only use React to add interactivity to existing HTML pages. They have many root components instead of a single one for the entire page. You can use as much—or as little—React as you need.

回顾

你刚刚第一次尝到了 React 的滋味!让我们回顾一些关键点。

¥You’ve just gotten your first taste of React! Let’s recap some key points.

  • React 允许你为你的应用创建组件、可重用的 UI 元素。

    ¥React lets you create components, reusable UI elements for your app.

  • 在 React 应用中,每一块 UI 都是一个组件。

    ¥In a React app, every piece of UI is a component.

  • React 组件是常规的 JavaScript 函数,除了:

    ¥React components are regular JavaScript functions except:

    1. 它们的名称总是以大写字母开头。

      ¥Their names always begin with a capital letter.

    2. 它们返回 JSX 标记。

      ¥They return JSX markup.

挑战 1 / 4:
导出组件

¥Export the component

此沙箱不起作用,因为未导出根组件:

¥This sandbox doesn’t work because the root component is not exported:

function Profile() {
  return (
    <img
      src="https://i.imgur.com/lICfvbD.jpg"
      alt="Aklilu Lemma"
    />
  );
}

在查看解决方案之前尝试自己修复它!

¥Try to fix it yourself before looking at the solution!


React 中文网 - 粤ICP备13048890号