React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?

系列回顾:

在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒,但一个真实的React应用是由许多组件组合而成的,就像搭积木一样。如果这些"积木"之间不能互相沟通、传递信息,那我们就无法搭建出复杂的结构。

欢迎来到React学习的第三站!

今天,我们要学习组件之间最基本、最重要的一种沟通方式:父组件向子组件传递数据 。而实现这种沟通的"信使",就是 Props

什么是Props?

Props (是 Properties 的缩CR) 就像是你在调用一个JavaScript函数时传递的参数。在React中,它就是父组件在调用子组件时,传递给子组件的"属性"或"数据"。

核心思想:

  • 父组件拥有数据。
  • 父组件通过属性的方式,把数据"塞"给子组件。
  • 子组件 通过一个叫做props的对象,接收并使用这些数据。

一个重要的原则:Props是只读的。 子组件只能读取和使用从父组件传来的Props,但绝对不能修改它。这保证了数据流的单向性(从上到下),让应用状态更可预测。


实战:创建一个用户卡片

让我们通过一个非常常见的案例------"用户卡片"------来学习Props的用法。我们将创建一个UserProfile子组件,它专门用来显示用户的头像和名字。而用户的具体信息(头像URL和名字)将由它的父组件App来提供。

第一步:创建子组件 UserProfile.jsx

  1. 在你的项目里,找到 src 文件夹。

  2. src 文件夹下,右键 -> 新建文件,命名为 UserProfile.jsx

  3. 将下面的代码复制到 UserProfile.jsx 文件中:

    jsx 复制代码
    // src/UserProfile.jsx
    
    function 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.avatarUrlprops.name来使用这些数据。
    • className是React中用来指定CSS类名的方式,它对应HTML中的class属性。

第二步:在父组件 App.jsx 中使用子组件并传递Props

现在,回到我们的App.jsx文件。我们将在这里"调用"刚刚创建的UserProfile组件,并像给HTML标签添加属性一样,把数据传递给它。

  1. 清空 App.jsx 并写入以下代码:

    jsx 复制代码
    // src/App.jsx
    
    import './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;

    代码解释:

    1. import UserProfile from './UserProfile';: 我们首先需要像导入普通模块一样,把子组件导入进来。
    2. 在JSX中,我们像使用一个自定义的HTML标签一样使用<UserProfile />
    3. 最关键的一步: 我们添加了nameavatarUrl这两个"属性"。
      • name={userInfo.name}: 这表示我们要传递一个名为name的prop,它的值是userInfo.name这个JavaScript变量的值。
      • avatarUrl={userInfo.avatarUrl}: 同理,传递一个名为avatarUrl的prop。

第三步:添加一点样式

为了让卡片更好看,我们给App.css添加一点简单的样式。打开src/App.css,用下面的代码替换原有内容:

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支持的类型。

jsx 复制代码
<UserProfile
  name="Tom"          // 字符串
  age={25}             // 数字 (注意使用花括号)
  isMember={true}      // 布尔值
  hobbies={['coding', 'reading']} // 数组
  profile={{ job: 'developer' }} // 对象
  sayHi={() => alert('Hello!')} // 函数
/>

2. 使用Props解构赋值,让代码更简洁

在子组件中,每次都写props.name有点繁琐。我们可以使用JS的解构赋值来简化它。

修改UserProfile.jsx

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开发中非常推荐的做法。


总结与思考

今天,我们掌握了组件化开发中最重要的一环------组件间的通信。回顾一下核心知识:

  1. Props是什么? 它是父组件传递给子组件的数据,就像函数的参数。
  2. 如何传递Props? 在使用子组件时,像写HTML属性一样把数据"塞"进去:<MyComponent propName={value} />
  3. 如何接收Props? 子组件的函数接收一个props对象作为参数,通过props.propName来访问数据。
  4. Props是只读的! 子组件不能修改从父组件接收到的Props。

我们现在已经学会了组件的"自力更生"(State)和"向父辈求助"(Props)。但是,一个有生命力的应用,还需要能响应用户的各种操作,比如点击、输入等等。

在下一篇文章 《React事件处理:如何给按钮绑定onClick点击事件?》 中,我们将学习如何让我们的组件"听懂"用户的指令,从而构建出真正可交互的应用。我们下期再会!

相关推荐
三门13 分钟前
docker安装mysql8.0.20过程
前端
方圆工作室17 分钟前
HTML实现的2048游戏
javascript·游戏·html
vvilkim20 分钟前
Flutter 核心概念:深入理解 StatelessWidget 与 StatefulWidget
开发语言·javascript·flutter
sunly_23 分钟前
Flutter:导航背景固定在顶部,下拉分页布局
开发语言·javascript·flutter
charlee4435 分钟前
给Markdown渲染网页增加一个目录组件(Vite+Vditor+Handlebars)(上)
javascript·vite·markdown·vditor·handlebars
BillKu1 小时前
Vue3 + Vite 中使用 Lodash-es 的防抖 debounce 详解
前端·javascript·vue.js
一只小风华~1 小时前
HTML前端开发:JavaScript的条分支语句if,Switch
前端·javascript·html5
橙子家1 小时前
Select 组件实现【全选】(基于 Element)
前端
超级土豆粉1 小时前
HTML 语义化
前端·html
bingbingyihao1 小时前
UI框架-通知组件
前端·javascript·vue