Table of Contents

1、概述

props 除了可以传递数据,还可以传递组件。

props 中,有一个特殊的字段 children,表示组件嵌套关系中的子元素。请注意,这里我的用词,嵌套关系中的子元素,我们不能笼统的认为 children 就是组件的子元素,这样很容易在后续更高阶的学习中,产生误解。

例如,我们有一个 Button 组件,它的写法如下

code.ts
1
<Button>
2
<span>Click me</span>
3
</Button>

此时,我们就可以称 spanButton 组件的子元素。再次强调,这里表达的是一种结构上的嵌套关系。

有了这个基础知识之后,我们就可以通过 children 来简化复杂组件的写法。我们可以单独将子组件抽离出去,通过 children 传进来,从而实现组件的复用与逻辑结构的简化。

2、容器组件

能够接收 children 的组件,我们称之为容器组件。

例如,我们有一个 Card 组件,它的写法如下,这种情况下,Card 组件就是一个容器组件。容器组件通常与视觉上的理解是一致的,通常表达一种包含关系。

code.ts
1
<Card>
2
<div>Card Content</div>
3
</Card>

在日常工作中,容器组件并没有特别明确的定义,因此很多时候就是一种约定俗成的称呼,表达一种可以包含别的组件的组件。

例如我们在整个页面中,封装一个 PageLayout 组件

code.ts
1
<PageLayout>
2
<div>Page Layout Content</div>
3
</PageLayout>

或者封装一个弹窗提示组件 Modal

code.ts
1
<Modal>
2
<div>Modal Content</div>
3
</Modal>

3、Card 组件的封装

这里,我们以 Card 组件的封装为例,来详细给大家介绍 children 的运用。

先看一下完整的代码,然后我们再逐步分析。

预览
card.tsx
app.tsx
1
import { PropsWithChildren } from 'react'
2
3
interface CardProps extends PropsWithChildren {
4
title: string
5
}
6
7
export default function Card(props: CardProps) {
8
const { children, title } = props
9
10
return (
11
<div className='border dark:border-0 border-gray-200 dark:inset-ring dark:inset-ring-white/10 rounded-xl'>
12
<header className='border-b border-gray-200 dark:border-white/10 p-4 font-bold'>
13
{title}
14
</header>
15
<div className='p-2'>
16
{children}
17
</div>
18
</div>
19
)
20
}
21

children 包含在 props 中,因此在使用时,直接通过 props.children 来获取即可。

在使用之前,我们需要定义一个包含了 childrenprops 类型,这里我们使用 PropsWithChildren 类型。

code.ts
1
import { PropsWithChildren } from 'react'
2
3
interface CardProps extends PropsWithChildren {
4
title: string
5
}

然后在组件中,我们就可以通过 props.children 来获取子元素即可。

code.ts
1
export default function Card(props: CardProps) {
2
const { children, title } = props
3
...
4
}

然后再补充一点样式,新增一些自定义的属性传入,例如 title 等。就可以正常使用了。例如

app.tsx
1
import Card from './card'
2
3
export default function App() {
4
const darkURL = 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*LT2jR41Uj2EAAAAAAAAAAAAADrJ8AQ/original'
5
const lightURL = 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*MLt3R6m9huoAAAAAAAAAAAAADrJ8AQ/original'
6
7
const themeMediaQuery = window.matchMedia('(prefers-color-scheme: light)')
8
9
const url = themeMediaQuery.matches ? lightURL : darkURL
10
11
return (
12
<div className='flex items-center gap-4'>
13
<Card title='Typography 排版'>
14
<div className='w-56 p-4'>
15
<img src={url} alt='card' className='m-auto w-44' />
16
</div>
17
</Card>
18
</div>
19
)
20
}

4、总结

children 在日常工作中的运用比较简单,但是他是讲复杂结构进行拆分的重要手段。因此在封装自定义组件时会被大量使用。

专栏首页
到顶
专栏目录