第10章 组件与Props
React 组件的基本概念和属性传递
作者:zyyc-0336 | 日期:2026-06-12
前置依赖:第9章 React 介绍与 JSX
下一章:第11章 State 与交互
📋 学习路径建议
- 先学 10.1.1(函数组件定义),掌握组件的基本写法
- 再学 10.1.2-10.1.3(Props 传递和默认值),学会组件之间传数据
- 最后学 10.1.4(children),理解"嵌套内容"的传递
⚠️ 常见错误提示
- 组件名必须大写字母开头,
<PostCard />✅,<postCard />❌ - Props 是只读的,组件内部不能修改 Props
- 传 Props 时,字符串用引号,其他类型用
{}:title="Hello"vscount={'{'}5{'}'} - 组件返回的 JSX 只能有一个根元素
10.1 组件与 Props
组件是 React 的积木,Props 是积木之间的接口
10.1.1 函数组件定义
组件就是一个返回 JSX 的函数。它接收数据(Props),输出一段界面。就像一个"机器"——你给它原料(数据),它给你产品(界面)。
// 最简单的组件
function Welcome() {
return <h1>欢迎来到我的博客!</h1>;
}
// 使用组件(像标签一样用)
<Welcome />
组件的命名规则
| 规则 | 正确 | 错误 |
|---|---|---|
| 大写字母开头 | PostCard | postCard |
| 有意义的名字 | ArticleList | MyComponent |
| 驼峰命名 | NavBar | nav-bar |
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>组件定义示例</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
// ========== 组件定义 ==========
// 博客标题组件
function BlogTitle() {
return <h1>📝 我的技术博客</h1>;
}
// 博客简介组件
function BlogIntro() {
return (
<p style={{ color: '#666', fontSize: '16px' }}>
分享前端开发知识,记录学习笔记。
</p>
);
}
// 底部版权组件
function Footer() {
return (
<footer style={{ marginTop: '40px', color: '#999', fontSize: '14px' }}>
<hr />
<p>© 2026 我的博客. All rights reserved.</p>
</footer>
);
}
// 组合使用
function App() {
return (
<div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<BlogTitle />
<BlogIntro />
<hr />
<p>这里将来会放文章列表...</p>
<Footer />
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>
代码逐行讲解
| 代码 | 说明 |
|---|---|
function BlogTitle() | 定义组件——一个返回 JSX 的函数 |
return <h1>...</h1> | 返回界面结构 |
<BlogTitle /> | 使用组件——像 HTML 标签一样写 |
<App /> | 在顶层组合所有子组件 |
💡 组件就像"自定义标签"。定义一次,到处使用。
10.1.2 Props 传递
Props(properties 的缩写)是父组件传给子组件的数据。就像函数的参数一样,让组件变得灵活。
// 子组件接收 Props
function PostCard(props) {
return <h2>{'{'}props.title{'}'}</h2>;
}
// 父组件传递 Props
<PostCard title="JavaScript入门" />
// 解构写法(推荐,更清晰)
function PostCard({ title, excerpt, date, author }) {
return (
<div style={{ border: '1px solid #e0e0e0', borderRadius: '8px',
padding: '20px', marginBottom: '16px' }}>
<h2>{'{'}title{'}'}</h2>
<p>✍️ {'{'}author{'}'} · 📅 {'{'}date{'}'}</p>
<p>{'{'}excerpt{'}'}</p>
<a href="#">阅读全文 →</a>
</div>
);
}
// 父组件传递 Props
function App() {
return (
<div>
<h1>文章列表</h1>
<PostCard
title="JavaScript 入门指南"
author="小明"
date="2026-06-01"
excerpt="零基础学习 JavaScript 的基础语法..."
/>
</div>
);
}
Props 传递方式
| 方式 | 语法 | 示例 |
|---|---|---|
| 字符串 | prop="值" | title="Hello" |
| 数字 | prop={'{数值}'} | count={'{5}'} |
| 布尔值 | prop={'{true}'} 或简写 prop | isPublished={'{true}'} |
| 对象 | prop={'{对象}'} | style={'{{ color: \'red\' }}'} |
| 数组 | prop={'{数组}'} | items={'{[\'a\', \'b\']}'} |
| 函数 | prop={'{函数}'} | onClick={'{() => alert(1)}'} |
⚠️ 新手易错:Props 是只读的,子组件不能修改 Props。这就像函数参数——你可以用它,但不能改它。想改就用 State(下一章讲)。
10.1.3 默认值与类型
当父组件没有传某个 Prop 时,子组件可以设置默认值。
// 设置默认值(解构时直接赋值)
function PostCard({
title = '无标题',
author = '匿名',
date = '未知日期',
excerpt = '暂无摘要',
views = 0
}) {
return (
<div>
<h3>{'{'}title{'}'}</h3>
<p>{'{'}author{'}'} · {'{'}date{'}'} · 👁️ {'{'}views{'}'} 次浏览</p>
<p>{'{'}excerpt{'}'}</p>
</div>
);
}
function App() {
return (
<div>
{/* 传了所有 Props */}
<PostCard title="完整文章" author="小明"
date="2026-06-12" excerpt="这篇文章传了所有 Props"
views={1500} />
{/* 只传部分,其余用默认值 */}
<PostCard title="部分 Props" excerpt="只传了标题和摘要" />
{/* 什么都不传,全部用默认值 */}
<PostCard />
</div>
);
}
运行结果
┌──────────────────────────────┐ │ 完整文章 │ │ 小明 · 2026-06-12 · 👁️ 1500 │ │ 这篇文章传了所有 Props │ └──────────────────────────────┘ ┌──────────────────────────────┐ │ 部分 Props │ │ 匿名 · 未知日期 · 👁️ 0 │ │ 只传了标题和摘要 │ └──────────────────────────────┘ ┌──────────────────────────────┐ │ 无标题 │ │ 匿名 · 未知日期 · 👁️ 0 │ │ 暂无摘要 │ └──────────────────────────────┘
10.1.4 children
children是一个特殊的 Prop——组件标签之间的内容。就像 HTML 标签可以包含内容一样,React 组件也可以。
// children 就是标签之间的内容
<Card>
<h1>这是 children</h1>
<p>这也是 children</p>
</Card>
// ========== 卡片容器组件 ==========
// children 是"中间的内容",由父组件决定
function Card({ title, children }) {
return (
<div style={{
border: '1px solid #ddd', borderRadius: '8px',
padding: '20px', marginBottom: '16px',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}}>
<h2>{'{'}title{'}'}</h2>
{/* children 在这里渲染 */}
<div>{'{'}children{'}'}</div>
</div>
);
}
// ========== 按钮组件 ==========
function Button({ variant = 'primary', children, ...rest }) {
let colors = {
primary: { bg: '#3498db', color: 'white' },
danger: { bg: '#e74c3c', color: 'white' },
success: { bg: '#2ecc71', color: 'white' }
};
let style = colors[variant] || colors.primary;
return (
<button style={{
padding: '8px 16px', backgroundColor: style.bg,
color: style.color, border: 'none',
borderRadius: '4px', cursor: 'pointer',
marginRight: '8px'
}} {'{'}...rest{'}'}>
{'{'}children{'}'}
</button>
);
}
// ========== 使用 ==========
function App() {
return (
<div>
<Card title="文章标题">
<p>这是卡片的内容,通过 children 传入。</p>
<p>可以放任何 JSX 内容。</p>
</Card>
<Card title="操作面板">
<p>请选择操作:</p>
<Button variant="primary">确认</Button>
<Button variant="danger">删除</Button>
<Button variant="success">保存</Button>
</Card>
</div>
);
}
children 的使用场景
| 场景 | 说明 |
|---|---|
| 容器组件 | <Card> 只管样式,不管内容 |
| 按钮组件 | <Button> 只管样式和行为,文字由 children 决定 |
| 布局组件 | <Layout> 只管布局,内容随意 |
| 弹窗组件 | <Modal> 只管弹窗框架,内容自定义 |
💡
children让组件变成"容器"——你决定结构和样式,使用者决定内容。这就是组件复用的核心思想。
本章复盘——组件与 Props 核心要点
| 要点 | 说明 |
|---|---|
| 组件定义 | 函数组件就是返回 JSX 的函数,大写字母开头 |
| Props | 父组件传给子组件的数据,只读不可修改 |
| 解构 Props | function Comp({'{ title, author }'}) {} 推荐写法 |
| 默认值 | 解构时直接赋默认值 title = '无标题' |
| children | 特殊 Prop,代表组件标签之间的内容 |
| 使用组件 | <PostCard title="Hello" />,像 HTML 标签一样 |
下一章预告(第11章):我们将学习useEffect 与生命周期——副作用处理、数据获取和组件生命周期管理。
本文档由 zyyc-0336 编写,最后更新:2026-06-14