react 将 Props 传递给组件

Posted on 2026-04-02 14:37  打杂滴  阅读(1)  评论(0)    收藏  举报

React 组件使用 props 来互相通信每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。Props 可能会让你想起 HTML 属性,但你可以通过它们传递任何 JavaScript 值,包括对象、数组和函数。

‌React 中的 props 是父组件向子组件传递数据的“输入参数”‌,它是只读的、用于实现组件间通信的核心机制。

你可以把 props 想象成调用函数时传入的参数:父组件通过 JSX 属性的形式,把字符串、数字、对象、函数等任意类型的数据传给子组件,子组件接收后根据这些数据来渲染 UI 或执行逻辑 。

 

核心特点:
‌单向数据流‌:数据只能从父组件流向子组件,不能反向修改 。
‌只读性‌:子组件不能直接修改 props,否则会破坏数据一致性。如果需要更新,应由父组件修改 state 并重新传递 。
‌灵活传递‌:支持传递基本类型(如字符串、数字)、引用类型(如对象、数组)甚至函数 。

熟悉的 props
Props 是你传递给 JSX 标签的信息。例如,className、src、alt、width 和 height 便是一些可以传递给 <img> 的 props

function Avatar() {
return (
<img
className="avatar"
src="https://i.imgur.com/1bX5QH6.jpg"
alt="Lin Lanying"
width={80}
height={80}
/>
);
}

export default function Profile() {
return (
<Avatar />
);
}

image

 你可以传递给 <img> 标签的 props 是预定义的(ReactDOM 符合 HTML 标准)。但是你可以将任何 props 传递给 你自己的 组件,例如 <Avatar> ,以便自定义它们。

向组件传递 props


在这段代码中, Profile 组件没有向它的子组件 Avatar 传递任何 props

export default function Profile() {
return (
<Avatar />
);
}

你可以分两步给 Avatar 一些 props。

步骤 1: 将 props 传递给子组件 

首先,将一些 props 传递给 Avatar。例如,让我们传递两个 props:person(一个对象)和 size(一个数字):

export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
如果 person= 后面的双花括号让你感到困惑,请记住,在 JSX 花括号中,它们只是一个对象。
现在,你可以在 Avatar 组件中读取这些 props 了。

步骤 2: 在子组件中读取 props
你可以通过在 function Avatar 之后直接列出它们的名字 person, size 来读取这些 props。这些 props 在 ({ 和 }) 之间,并由逗号分隔。这样,你可以在 Avatar 的代码中使用它们,就像使用变量一样。

function Avatar({ person, size }) {
// 在这里 person 和 size 是可访问的
}
向使用 person 和 size props 渲染的 Avatar 添加一些逻辑,你就完成了。

 

utils.js:

export function getImageUrl(person, size = 's') {
return (
'https://i.imgur.com/' +
person.imageId +
size +
'.jpg'
);
}

 

App.js:

import { getImageUrl } from './utils.js';

function Avatar({ person, size }) {
return (
<img
className="avatar"
src={getImageUrl(person)}
alt={person.name}
width={size}
height={size}
/>
);
}

export default function Profile() {
return (
<div>
<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>
<Avatar
size={30}
person={{
name: 'Aklilu Lemma',
imageId: 'OKS67lh'
}}
/>
<Avatar
size={50}
person={{
name: 'Lin Lanying',
imageId: '1bX5QH6'
}}
/>
</div>
);
}

image

 

上述实例中,props的传递过程‌遵循了React组件数据流的“自上而下”原则。这个过程可以清晰地分为三个步骤:‌定义、传递和接收‌。

1. Props的定义(在父组件中)
Props(属性)的数据源在父组件 Profile 中被定义。您创建了三个对象,每个对象都包含了要传递给子组件 Avatar 的具体数据。

‌第一个Avatar的props‌:
size: 100
person: { name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }
‌第二个Avatar的props‌:
size: 30
person: { name: 'Aklilu Lemma', imageId: 'OKS67lh' }
‌第三个Avatar的props‌:
size: 50
person: { name: 'Lin Lanying', imageId: '1bX5QH6' }
2. Props的传递(从父组件到子组件)
在父组件 Profile 的JSX中,通过‌类似于HTML属性的语法‌将上述数据传递给子组件 Avatar。

<Avatar
size={100} // 传递名为size的prop,其值为数字100
person={{ // 传递名为person的prop,其值为一个对象
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>
这段代码可以理解为:调用(渲染)Avatar 组件,并给它两个“参数”:size 和 person。

3. Props的接收与使用(在子组件中)
子组件 Avatar 通过其‌函数参数‌来接收父组件传递过来的所有props。React会将所有传递的属性打包成一个对象,作为第一个参数传入组件函数。

function Avatar({ person, size }) {
// 这里使用了“解构赋值”语法,直接从props对象中提取出person和size两个变量。
// 等效于:
// function Avatar(props) {
// const person = props.person;
// const size = props.size;
// }

return (
<img
className="avatar"
src={getImageUrl(person)} // 使用接收到的person prop
alt={person.name} // 使用接收到的person prop中的name属性
width={size} // 使用接收到的size prop
height={size} // 使用接收到的size prop
/>
);
}

传递过程总结与可视化
我们可以将整个过程想象成一个‌函数调用链‌:

‌父组件(调用者)‌:Profile 组件决定要渲染什么,并准备好数据(size 和 person 对象)。
‌传递(调用语句)‌:在JSX中书写 <Avatar size={...} person={...} />,这就像执行了一个函数调用 Avatar({size: ..., person: ...})。
‌子组件(函数定义)‌:Avatar 组件函数被调用,接收到的参数(即props对象)包含了所有传入的数据。
‌子组件(内部执行)‌:Avatar 组件使用这些数据来构建它的返回值(一段描述头像图片的JSX)。
‌关键特性‌:

‌单向数据流‌:数据只能从父组件(Profile)流向子组件(Avatar)。子组件不能直接修改接收到的props,它们是‌只读的‌。
‌动态与复用‌:通过传递不同的props,同一个 Avatar 组件可以渲染出无数个不同的头像实例。这正是React组件‌可复用性‌的核心。
‌任意数据类型‌:Props可以传递任何JavaScript值,包括字符串、数字、对象、数组,甚至是函数或JSX。
在您的例子中,正是通过这种props传递机制,Profile 组件成功地将三位科学家的不同姓名、头像ID和显示尺寸,精确地传递给了三个独立的 Avatar 组件实例,从而在页面上渲染出三个各不相同的头像。

 

将 JSX 作为子组件传递

嵌套浏览器内置标签是很常见的:

<div>
<img />
</div>
有时你会希望以相同的方式嵌套自己的组件:

<Card>
<Avatar />
</Card>
当你将内容嵌套在 JSX 标签中时,父组件将在名为 children 的 prop 中接收到该内容。例如,下面的 Card 组件将接收一个被设为 <Avatar /> 的 children prop 并将其包裹在 div 中渲染:

utils.js
export function getImageUrl(person, size = 's') {
  return (
    'https://i.imgur.com/' +
    person.imageId +
    size +
    '.jpg'
  );
}
Avatar.js
import { getImageUrl } from './utils.js';

export default function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}
app.js
import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}
 
 

尝试用一些文本替换 <Card> 中的 <Avatar>,看看 Card 组件如何包裹任意嵌套内容。它不必“知道”其中渲染的内容。你会在很多地方看到这种灵活的模式。

可以将带有 children prop 的组件看作有一个“洞”,可以由其父组件使用任意 JSX 来“填充”。你会经常使用 children prop 来进行视觉包装:面板、网格等等。

 

utils.js

export function getImageUrl(imageId, size = 's') {
return (
'https://i.imgur.com/' +
imageId +
size +
'.jpg'
);
}

App.js

import { getImageUrl } from './utils.js';

function Profile({name,imageId,Profession,Awards,size
                 ,Discovered}){
  return (
    <section className="profile">
        <h2>{name}</h2>
        <img
          className="avatar"
          src={getImageUrl(imageId)}
          alt={name}
          width={size}
          height={size}
        />
        <ul>
          <li>
            <b>Profession: </b>
             {Profession}
          </li>
          <li>
            <b>Awards: 4 </b>
             {Awards}
          </li>
          <li>
            <b>Discovered: </b>
            {Discovered}
          </li>
        </ul>
      </section>
  )
}

export default function Gallery() {
  return (
    <div>
      <h1>Notable Scientists</h1>
      <Profile
        name="tian"
        imageId="szV5sdG"
        Profession="dddd"
        Awards="ggg"
        size="50"
        Discovered="ddd"
        ></Profile>
        <Profile
        name="wang"
        imageId="szV5sdG"
        Profession="dggdag"
        Awards="dagag"
        size="50"
        Discovered="ddasgdagddd"
        ></Profile>
    </div>
  );
}

image

 

 

 

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3