组件的魔力在于其可复用性:你可以创建由其他组件组成的组件。但随着你嵌套越来越多的组件,通常把它们拆分到不同文件中会更合理。这可以让你的文件更易于浏览,并在更多地方复用组件。
You will learn
- 什么是根组件文件
- 如何导入和导出组件
- 何时使用默认导入/导出和命名导入/导出
- 如何从一个文件中导入和导出多个组件
- 如何将组件拆分到多个文件中
根组件文件
在 你的第一个组件 中,你创建了一个 Profile 组件和一个渲染它的 Gallery 组件:
function Profile() { return ( <img src="https://react.dev/images/docs/scientists/MK3eW3As.jpg" alt="Katherine Johnson" /> ); } export default function Gallery() { return ( <section> <h1>令人惊叹的科学家</h1> <Profile /> <Profile /> <Profile /> </section> ); }
这些内容目前位于一个根组件文件中,在这个示例里它的名字是 App.js。不过,具体取决于你的设置,根组件也可能位于其他文件中。如果你使用的是基于文件路由的框架,例如 Next.js,那么每个页面的根组件都不同。
导出和导入组件
如果你将来想把着陆页改成展示一份科学书籍列表呢?或者把所有个人资料放到别的地方呢?把 Gallery 和 Profile 移出根组件文件是很合理的。这样可以让它们更模块化,也更容易在其他文件中复用。你可以分三步移动一个组件:
这里,Profile 和 Gallery 都已经从 App.js 移动到了一个名为 Gallery.js 的新文件中。现在你可以修改 App.js,从 Gallery.js 导入 Gallery:
import Gallery from './Gallery.js'; export default function App() { return ( <Gallery /> ); }
注意这个示例现在被拆分成了两个组件文件:
Gallery.js:- 定义了
Profile组件,它仅在同一个文件中使用,并且没有被导出。 - 将
Gallery组件作为默认导出导出。
- 定义了
App.js:- 从
Gallery.js中将Gallery作为默认导入导入。 - 将根
App组件作为默认导出导出。
- 从
Deep Dive
用 JavaScript 导出值主要有两种方式:默认导出和命名导出。到目前为止,我们的示例只使用了默认导出。但你可以在同一个文件中使用其中一种或两种。一个文件最多只能有一个 默认 导出,但可以拥有任意多个 命名 导出。
你如何导出组件,决定了你必须如何导入它。如果你尝试以命名导出的方式导入默认导出,就会报错!这个表格可以帮助你区分:
| 语法 | 导出语句 | 导入语句 |
|---|---|---|
| 默认 | export default function Button() {} | import Button from './Button.js'; |
| 命名 | export function Button() {} | import { Button } from './Button.js'; |
当你写一个 默认 导入时,import 后面可以使用任何你想要的名字。例如,你也可以写成 import Banana from './Button.js',它仍然会给你同样的默认导出。相反,对于命名导入,两边的名字必须匹配。这就是它们被称为 命名 导入的原因!
如果文件只导出一个组件,人们通常会使用默认导出;如果文件导出多个组件和其他值,则通常使用命名导出。 无论你偏好哪种编码风格,都要始终给组件函数以及包含它们的文件起有意义的名字。像 export default () => {} 这样的无名组件不被推荐,因为它们会让调试更困难。
从同一个文件中导出和导入多个组件
如果你只想显示一个 Profile,而不是一个画廊呢?你也可以导出 Profile 组件。不过 Gallery.js 已经有一个 默认 导出了,你不能有 两个 默认导出。你可以创建一个带默认导出的新文件,或者给 Profile 添加一个 命名 导出。一个文件只能有一个默认导出,但可以有很多命名导出!
首先,使用命名导出从 Gallery.js 导出 Profile(不使用 default 关键字):
export function Profile() {
// ...
}然后,使用命名导入(带花括号)将 Profile 从 Gallery.js 导入到 App.js:
import { Profile } from './Gallery.js';最后,从 App 组件中渲染 <Profile />:
export default function App() {
return <Profile />;
}现在 Gallery.js 包含两个导出:一个默认的 Gallery 导出,以及一个命名的 Profile 导出。App.js 同时导入了它们。尝试在这个示例中把 <Profile /> 改成 <Gallery />,再改回来:
import Gallery from './Gallery.js'; import { Profile } from './Gallery.js'; export default function App() { return ( <Profile /> ); }
现在你正在混合使用默认导出和命名导出:
Gallery.js:- 将
Profile组件作为一个名为Profile的命名导出导出。 - 将
Gallery组件作为默认导出导出。
- 将
App.js:- 从
Gallery.js中将Profile作为一个名为Profile的命名导入导入。 - 从
Gallery.js中将Gallery作为默认导入导入。 - 将根
App组件作为默认导出导出。
- 从
Recap
在本页中你学到了:
- 什么是根组件文件
- 如何导入和导出组件
- 何时以及如何使用默认导入/导出和命名导入/导出
- 如何从同一个文件中导出多个组件
Challenge 1 of 1: 进一步拆分组件
目前,Gallery.js 同时导出 Profile 和 Gallery,这有点让人困惑。
把 Profile 组件移动到它自己的 Profile.js 中,然后把 App 组件改为依次渲染 <Profile /> 和 <Gallery />。
你可以为 Profile 使用默认导出或命名导出,但请确保在 App.js 和 Gallery.js 中使用对应的导入语法!你可以参考上面深度解析中的表格:
| 语法 | 导出语句 | 导入语句 |
|---|---|---|
| 默认 | export default function Button() {} | import Button from './Button.js'; |
| 命名 | export function Button() {} | import { Button } from './Button.js'; |
// 把我移动到 Profile.js! export function Profile() { return ( <img src="https://react.dev/images/docs/scientists/QIrZWGIs.jpg" alt="Alan L. Hart" /> ); } export default function Gallery() { return ( <section> <h1>令人惊叹的科学家</h1> <Profile /> <Profile /> <Profile /> </section> ); }
在先用一种导出方式把它做通之后,再用另一种方式实现一次。