组件的神奇之处在于它们的可重用性:你可以创建由其他组件组成的组件。但是当你嵌套越来越多的组件时,开始将它们拆分成不同的文件通常是有意义的。这使你可以使文件易于扫描并在更多地方重复使用组件。
¥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
如果你想在未来改变登陆屏幕并在那里放一个科学书籍列表怎么办?或者将所有配置文件放在其他地方?将 Gallery
和 Profile
移出根组件文件是有意义的。这将使它们更加模块化并可在其他文件中重用。你可以分三步移动组件:
¥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:
-
创建一个新的 JS 文件来放入组件。
¥Make a new JS file to put the components in.
-
¥Export your function component from that file (using either default or named exports).
-
将其导入到你将使用该组件的文件中(使用导入 默认 或 命名 导出的相应技术)。
¥Import it in the file where you’ll use the component (using the corresponding technique for importing default or named exports).
这里 Profile
和 Gallery
都已从 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:
-
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.
-
-
App.js
:-
从
Gallery.js
导入Gallery
作为默认导入。¥Imports
Gallery
as a default import fromGallery.js
. -
将根
App
组件导出为默认导出。¥Exports the root
App
component as a default export.
-
深入研究
¥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.
你如何导出组件决定了你必须如何导入它。如果你尝试以与命名导出相同的方式导入默认导出,则会出现错误!此图表可以帮助你跟踪:
¥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!
首先,使用命名导出从 Gallery.js
导出 Profile
(无 default
关键字):
¥First, export Profile
from Gallery.js
using a named export (no default
keyword):
export function Profile() {
// ...
}
然后,使用命名导入(带有大括号)将 Profile
从 Gallery.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 calledProfile
. -
将
Gallery
组件导出为默认导出。¥Exports the
Gallery
component as a default export.
-
-
App.js
:-
将
Profile
作为名为Profile
的命名导入从Gallery.js
导入。¥Imports
Profile
as a named import calledProfile
fromGallery.js
. -
从
Gallery.js
导入Gallery
作为默认导入。¥Imports
Gallery
as a default import fromGallery.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
同时导出 Profile
和 Gallery
,这有点令人困惑。
¥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.js
和 Gallery.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.