导入和导出组件

组件的神奇之处在于它们的可重用性:你可以创建由其他组件组成的组件。但是当你嵌套越来越多的组件时,开始将它们拆分成不同的文件通常是有意义的。这使你可以使文件易于扫描并在更多地方重复使用组件。

¥The magic of components lies in their reusability: you can create components that are composed of other components. But as you nest more and more components, it often makes sense to start splitting them into different files. This lets you keep your files easy to scan and reuse components in more places.

你将学习到

  • 什么是根组件文件

    ¥What a root component file is

  • 如何导入和导出组件

    ¥How to import and export a component

  • 何时使用默认和命名的导入和导出

    ¥When to use default and named imports and exports

  • 如何从一个文件导入和导出多个组件

    ¥How to import and export multiple components from one file

  • 如何将组件拆分成多个文件

    ¥How to split components into multiple files

根组件文件

¥The root component file

你的第一个组件 中,你制作了一个 Profile 组件和一个渲染它的 Gallery 组件:

¥In Your First Component, you made a Profile component and a Gallery component that renders it:

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

这些当前位于根组件文件中,在此示例中名为 App.js。不过,根据你的设置,你的根组件可能位于另一个文件中。如果你使用基于文件的路由框架,例如 Next.js,你的根组件对于每个页面都会不同。

¥These currently live in a root component file, named App.js in this example. Depending on your setup, your root component could be in another file, though. If you use a framework with file-based routing, such as Next.js, your root component will be different for every page.

导出和导入组件

¥Exporting and importing a component

如果你想在未来改变登陆屏幕并在那里放一个科学书籍列表怎么办?或者将所有配置文件放在其他地方?将 GalleryProfile 移出根组件文件是有意义的。这将使它们更加模块化并可在其他文件中重用。你可以分三步移动组件:

¥What if you want to change the landing screen in the future and put a list of science books there? Or place all the profiles somewhere else? It makes sense to move Gallery and Profile out of the root component file. This will make them more modular and reusable in other files. You can move a component in three steps:

  1. 创建一个新的 JS 文件来放入组件。

    ¥Make a new JS file to put the components in.

  2. 从该文件导出你的函数组件(使用 默认命名 导出)。

    ¥Export your function component from that file (using either default or named exports).

  3. 将其导入到你将使用该组件的文件中(使用导入 默认命名 导出的相应技术)。

    ¥Import it in the file where you’ll use the component (using the corresponding technique for importing default or named exports).

这里 ProfileGallery 都已从 App.js 移出到一个名为 Gallery.js 的新文件中。现在你可以更改 App.js 以从 Gallery.js 导入 Gallery

¥Here both Profile and Gallery have been moved out of App.js into a new file called Gallery.js. Now you can change App.js to import Gallery from Gallery.js:

import Gallery from './Gallery.js';

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

注意这个例子现在是如何分解成两个组件文件的:

¥Notice how this example is broken down into two component files now:

  1. Gallery.js

    • 定义仅在同一文件中使用且不导出的 Profile 组件。

      ¥Defines the Profile component which is only used within the same file and is not exported.

    • Gallery 组件导出为默认导出。

      ¥Exports the Gallery component as a default export.

  2. App.js

    • Gallery.js 导入 Gallery 作为默认导入。

      ¥Imports Gallery as a default import from Gallery.js.

    • 将根 App 组件导出为默认导出。

      ¥Exports the root App component as a default export.

注意

你可能会遇到像这样没有 .js 文件扩展名的文件:

¥You may encounter files that leave off the .js file extension like so:

import Gallery from './Gallery';

'./Gallery.js''./Gallery' 都可以与 React 一起工作,尽管前者更接近 原生 ES 模块 的工作方式。

¥Either './Gallery.js' or './Gallery' will work with React, though the former is closer to how native ES Modules work.

深入研究

默认与命名导出

¥Default vs named exports

使用 JavaScript 导出值有两种主要方法:默认导出和命名导出。到目前为止,我们的示例只使用了默认导出。但是你可以在同一个文件中使用其中一个或两个。一个文件最多只能有一个默认导出,但它可以有任意多个命名导出。

¥There are two primary ways to export values with JavaScript: default exports and named exports. So far, our examples have only used default exports. But you can use one or both of them in the same file. A file can have no more than one default export, but it can have as many named exports as you like.

Default and named exports

你如何导出组件决定了你必须如何导入它。如果你尝试以与命名导出相同的方式导入默认导出,则会出现错误!此图表可以帮助你跟踪:

¥How you export your component dictates how you must import it. You will get an error if you try to import a default export the same way you would a named export! This chart can help you keep track:

语法导出声明导入声明
默认export default function Button() {}import Button from './Button.js';
命名export function Button() {}import { Button } from './Button.js';

当你写一个默认导入时,你可以在 import 后面放任何你想要的名字。例如,你可以改写 import Banana from './Button.js',它仍会为你提供相同的默认导出。但是,对于命名导入,名称必须在两侧匹配。这就是为什么它们被称为命名导入!

¥When you write a default import, you can put any name you want after import. For example, you could write import Banana from './Button.js' instead and it would still provide you with the same default export. In contrast, with named imports, the name has to match on both sides. That’s why they are called named imports!

如果文件仅导出一个组件,人们通常使用默认导出,如果导出多个组件和值,则使用命名导出。无论你喜欢哪种编码风格,请始终为你的组件函数和包含它们的文件提供有意义的名称。不鼓励使用没有名称的组件,例如 export default () => {},因为它们会使调试变得更加困难。

¥People often use default exports if the file exports only one component, and use named exports if it exports multiple components and values. Regardless of which coding style you prefer, always give meaningful names to your component functions and the files that contain them. Components without names, like export default () => {}, are discouraged because they make debugging harder.

从同一文件导出和导入多个组件

¥Exporting and importing multiple components from the same file

如果你只想展示一个 Profile 而不是图库怎么办?你也可以导出 Profile 组件。但是 Gallery.js 已经有一个默认导出了,你不能有两个默认导出。你可以创建一个带有默认导出的新文件,或者你可以为 Profile 添加一个命名导出。一个文件只能有一个默认导出,但它可以有多个命名导出!

¥What if you want to show just one Profile instead of a gallery? You can export the Profile component, too. But Gallery.js already has a default export, and you can’t have two default exports. You could create a new file with a default export, or you could add a named export for Profile. A file can only have one default export, but it can have numerous named exports!

注意

为了减少默认导出和命名导出之间的潜在混淆,一些团队选择只坚持一种风格(默认或命名),或者避免将它们混合在一个文件中。做最适合你的事情!

¥To reduce the potential confusion between default and named exports, some teams choose to only stick to one style (default or named), or avoid mixing them in a single file. Do what works best for you!

首先,使用命名导出从 Gallery.js 导出 Profile(无 default 关键字):

¥First, export Profile from Gallery.js using a named export (no default keyword):

export function Profile() {
// ...
}

然后,使用命名导入(带有大括号)将 ProfileGallery.js 导入到 App.js

¥Then, import Profile from Gallery.js to App.js using a named import (with the curly braces):

import { Profile } from './Gallery.js';

最后,从 App 组件渲染 <Profile />

¥Finally, render <Profile /> from the App component:

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

现在 Gallery.js 包含两个导出:默认的 Gallery 导出和命名的 Profile 导出。App.js 导入了它们。在此示例中尝试编辑 <Profile /><Gallery /> 并返回:

¥Now Gallery.js contains two exports: a default Gallery export, and a named Profile export. App.js imports both of them. Try editing <Profile /> to <Gallery /> and back in this example:

import Gallery from './Gallery.js';
import { Profile } from './Gallery.js';

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

现在你混合使用默认导出和命名导出:

¥Now you’re using a mix of default and named exports:

  • Gallery.js

    • Profile 组件导出为名为 Profile 的命名导出。

      ¥Exports the Profile component as a named export called Profile.

    • Gallery 组件导出为默认导出。

      ¥Exports the Gallery component as a default export.

  • App.js

    • Profile 作为名为 Profile 的命名导入从 Gallery.js 导入。

      ¥Imports Profile as a named import called Profile from Gallery.js.

    • Gallery.js 导入 Gallery 作为默认导入。

      ¥Imports Gallery as a default import from Gallery.js.

    • 将根 App 组件导出为默认导出。

      ¥Exports the root App component as a default export.

回顾

在此页面上,你了解到:

¥On this page you learned:

  • 什么是根组件文件

    ¥What a root component file is

  • 如何导入和导出组件

    ¥How to import and export a component

  • 何时以及如何使用默认和命名的导入和导出

    ¥When and how to use default and named imports and exports

  • 如何从同一个文件中导出多个组件

    ¥How to export multiple components from the same file

挑战 1 / 1:
进一步拆分组件

¥Split the components further

目前,Gallery.js 同时导出 ProfileGallery,这有点令人困惑。

¥Currently, Gallery.js exports both Profile and Gallery, which is a bit confusing.

Profile 组件移到自己的 Profile.js 上,然后更改 App 组件,依次渲染 <Profile /><Gallery />

¥Move the Profile component to its own Profile.js, and then change the App component to render both <Profile /> and <Gallery /> one after another.

你可以为 Profile 使用默认导出或命名导出,但请确保在 App.jsGallery.js 中都使用相应的导入语法!你可以参考上面深入研究的表格:

¥You may use either a default or a named export for Profile, but make sure that you use the corresponding import syntax in both App.js and Gallery.js! You can refer to the table from the deep dive above:

语法导出声明导入声明
默认export default function Button() {}import Button from './Button.js';
命名export function Button() {}import { Button } from './Button.js';
// Move me to Profile.js!
export function Profile() {
  return (
    <img
      src="https://i.imgur.com/QIrZWGIs.jpg"
      alt="Alan L. Hart"
    />
  );
}

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

在你让它与一种导出一起工作之后,让它与另一种导出一起工作。

¥After you get it working with one kind of exports, make it work with the other kind.


React 中文网 - 粤ICP备13048890号