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 />
);
}

你可以传递给 <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(一个数字):
步骤 2: 在子组件中读取 props
你可以通过在 function Avatar 之后直接列出它们的名字 person, size 来读取这些 props。这些 props 在 ({ 和 }) 之间,并由逗号分隔。这样,你可以在 Avatar 的代码中使用它们,就像使用变量一样。
function Avatar({ person, size }) {
// 在这里 person 和 size 是可访问的
}
向使用 person 和 size props 渲染的 Avatar 添加一些逻辑,你就完成了。
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>
);
}

上述实例中,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 中渲染:
尝试用一些文本替换 <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

浙公网安备 33010602011771号