React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾:
在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState
让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒,但一个真实的React应用是由许多组件组合而成的,就像搭积木一样。如果这些“积木”之间不能互相沟通、传递信息,那我们就无法搭建出复杂的结构。
欢迎来到React学习的第三站!
今天,我们要学习组件之间最基本、最重要的一种沟通方式:父组件向子组件传递数据。而实现这种沟通的“信使”,就是 Props。
什么是Props?
Props (是 Properties 的缩CR) 就像是你在调用一个JavaScript函数时传递的参数。在React中,它就是父组件在调用子组件时,传递给子组件的“属性”或“数据”。
核心思想:
- 父组件拥有数据。
- 父组件通过属性的方式,把数据“塞”给子组件。
- 子组件通过一个叫做
props
的对象,接收并使用这些数据。
一个重要的原则:Props是只读的。 子组件只能读取和使用从父组件传来的Props,但绝对不能修改它。这保证了数据流的单向性(从上到下),让应用状态更可预测。
实战:创建一个用户卡片
让我们通过一个非常常见的案例——“用户卡片”——来学习Props的用法。我们将创建一个UserProfile
子组件,它专门用来显示用户的头像和名字。而用户的具体信息(头像URL和名字)将由它的父组件App
来提供。
第一步:创建子组件 UserProfile.jsx
-
在你的项目里,找到
src
文件夹。 -
在
src
文件夹下,右键 -> 新建文件,命名为UserProfile.jsx
。 -
将下面的代码复制到
UserProfile.jsx
文件中:// src/UserProfile.jsxfunction UserProfile(props) {// 'props' 是一个对象,包含了父组件传递过来的所有属性console.log(props); // 可以在浏览器控制台看看 props 长什么样return (<div className="user-card"><img src={props.avatarUrl} alt={props.name} className="avatar" /><h2 className="user-name">{props.name}</h2></div>); }export default UserProfile;
代码解释:
- 我们的
UserProfile
组件接收一个参数props
。React会自动把父组件传递的所有属性打包成一个对象,放进这个props
里。 - 在JSX中,我们通过
props.avatarUrl
和props.name
来使用这些数据。 className
是React中用来指定CSS类名的方式,它对应HTML中的class
属性。
- 我们的
第二步:在父组件 App.jsx
中使用子组件并传递Props
现在,回到我们的App.jsx
文件。我们将在这里“调用”刚刚创建的UserProfile
组件,并像给HTML标签添加属性一样,把数据传递给它。
-
清空
App.jsx
并写入以下代码:// src/App.jsximport './App.css'; import UserProfile from './UserProfile'; // 1. 导入子组件function App() {const userInfo = {name: 'React 小白',avatarUrl: 'https://zh-hans.react.dev/images/logo.svg' // 使用React官方Logo作为头像};return (<div><h1>我的用户卡片</h1>{/* 2. 使用子组件,并像HTML属性一样传递props */}<UserProfile name={userInfo.name} avatarUrl={userInfo.avatarUrl} /></div>); }export default App;
代码解释:
import UserProfile from './UserProfile';
: 我们首先需要像导入普通模块一样,把子组件导入进来。- 在JSX中,我们像使用一个自定义的HTML标签一样使用
<UserProfile />
。 - 最关键的一步: 我们添加了
name
和avatarUrl
这两个“属性”。name={userInfo.name}
: 这表示我们要传递一个名为name
的prop,它的值是userInfo.name
这个JavaScript变量的值。avatarUrl={userInfo.avatarUrl}
: 同理,传递一个名为avatarUrl
的prop。
第三步:添加一点样式
为了让卡片更好看,我们给App.css
添加一点简单的样式。打开src/App.css
,用下面的代码替换原有内容:
/* src/App.css */
.user-card {border: 1px solid #ccc;border-radius: 8px;padding: 16px;text-align: center;width: 200px;margin: 20px auto;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}.avatar {width: 100px;height: 100px;border-radius: 50%;object-fit: cover;
}.user-name {margin-top: 12px;color: #333;
}
第四步:查看效果
现在,保存所有文件,回到你的浏览器。你应该能看到一个漂亮的用户卡片,上面有React的Logo和"React 小白"这个名字。
你已经成功地实现了父组件到子组件的数据传递!
Props的更多用法
1. 传递不同类型的数据
Props不仅可以传递字符串,还可以传递任何JavaScript支持的类型。
<UserProfilename="Tom" // 字符串age={25} // 数字 (注意使用花括号)isMember={true} // 布尔值hobbies={['coding', 'reading']} // 数组profile={{ job: 'developer' }} // 对象sayHi={() => alert('Hello!')} // 函数
/>
2. 使用Props解构赋值,让代码更简洁
在子组件中,每次都写props.name
有点繁琐。我们可以使用JS的解构赋值来简化它。
修改UserProfile.jsx
:
// function UserProfile(props) {
// 变为:
function UserProfile({ name, avatarUrl }) { // 直接在这里解构return (<div className="user-card">{/* 现在可以直接使用变量名 */}<img src={avatarUrl} alt={name} className="avatar" /><h2 className="user-name">{name}</h2></div>);
}
这样代码是不是清爽多了?这是现代React开发中非常推荐的做法。
总结与思考
今天,我们掌握了组件化开发中最重要的一环——组件间的通信。回顾一下核心知识:
- Props是什么? 它是父组件传递给子组件的数据,就像函数的参数。
- 如何传递Props? 在使用子组件时,像写HTML属性一样把数据“塞”进去:
<MyComponent propName={value} />
。 - 如何接收Props? 子组件的函数接收一个
props
对象作为参数,通过props.propName
来访问数据。 - Props是只读的! 子组件不能修改从父组件接收到的Props。
我们现在已经学会了组件的“自力更生”(State)和“向父辈求助”(Props)。但是,一个有生命力的应用,还需要能响应用户的各种操作,比如点击、输入等等。
在下一篇文章 《React事件处理:如何给按钮绑定onClick点击事件?》 中,我们将学习如何让我们的组件“听懂”用户的指令,从而构建出真正可交互的应用。我们下期再会!