React components use props to communicate with each other. Every parent component can pass some information to its child components by giving them props. Props might remind you of HTML attributes, but you can pass any JavaScript value through them, including objects, arrays, and functions. React 组件使用 props 来互相通信。每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。Props 可能会让你想起 HTML 属性,但你可以通过它们传递任何 JavaScript 值,包括对象、数组和函数。
你将会学习到
- How to pass props to a component
- 如何向组件传递 props
- How to read props from a component
- 如何从组件读取 props
- How to specify default values for props
- 如何为 props 指定默认值
- How to pass some JSX to a component
- 如何给组件传递 JSX
- How props change over time
- Props 如何随时间变化
熟悉的 props | Familiar props
Props are the information that you pass to a JSX tag. For example, className
, src
, alt
, width
, and height
are some of the props you can pass to an <img>
:
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={100} height={100} /> ); } export default function Profile() { return ( <Avatar /> ); }
The props you can pass to an <img>
tag are predefined (ReactDOM conforms to the HTML standard). But you can pass any props to your own components, such as <Avatar>
, to customize them. Here’s how!
你可以传递给 <img>
标签的 props 是预定义的(ReactDOM 符合 HTML 标准)。但是你可以将任何 props 传递给 你自己的 组件,例如 <Avatar>
,以便自定义它们。 就像这样!
向组件传递 props | Passing props to a component
In this code, the Profile
component isn’t passing any props to its child component, Avatar
:
在这段代码中, Profile
组件没有向它的子组件 Avatar
传递任何 props :
export default function Profile() {
return (
<Avatar />
);
}
You can give Avatar
some props in two steps.
你可以分两步给 Avatar
一些 props。
步骤 1: 将 props 传递给子组件 | Step 1: Pass props to the child component
First, pass some props to Avatar
. For example, let’s pass two props: person
(an object), and size
(a number):
首先,将一些 props 传递给 Avatar
。例如,让我们传递两个 props:person
(一个对象)和 size
(一个数字):
export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
Now you can read these props inside the Avatar
component.
现在,你可以在 Avatar
组件中读取这些 props 了。
步骤 2: 在子组件中读取 props | Step 2: Read props inside the child component
You can read these props by listing their names person, size
separated by the commas inside ({
and })
directly after function Avatar
. This lets you use them inside the Avatar
code, like you would with a variable.
你可以通过在 function Avatar
之后直接列出它们的名字 person, size
来读取这些 props。这些 props 在 ({
和 })
之间,并由逗号分隔。这样,你可以在 Avatar
的代码中使用它们,就像使用变量一样。
function Avatar({ person, size }) {
// person and size are available here
// 在这里 person 和 size 是可访问的
}
Add some logic to Avatar
that uses the person
and size
props for rendering, and you’re done.
向使用 person
和 size
props 渲染的 Avatar
添加一些逻辑,你就完成了。
Now you can configure Avatar
to render in many different ways with different props. Try tweaking the values!
现在你可以配置 Avatar
,通过不同的 props,使它能以多种不同的方式进行渲染。尝试变换值吧!
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={80} person={{ name: 'Aklilu Lemma', imageId: 'OKS67lh' }} /> <Avatar size={50} person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} /> </div> ); }
Props let you think about parent and child components independently. For example, you can change the person
or the size
props inside Profile
without having to think about how Avatar
uses them. Similarly, you can change how the Avatar
uses these props, without looking at the Profile
.
Props 使你独立思考父组件和子组件。 例如,你可以改变 Profile
中的 person
或 size
props,而无需考虑 Avatar
如何使用它们。 同样,你可以改变 Avatar
使用这些 props 的方式,不必考虑 Profile
。
You can think of props like “knobs” that you can adjust. They serve the same role as arguments serve for functions—in fact, props are the only argument to your component! React component functions accept a single argument, a props
object:
你可以将 props 想象成可以调整的“旋钮”。它们的作用与函数的参数相同 —— 事实上,props 正是 组件的唯一参数! React 组件函数接受一个参数,一个 props
对象:
function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}
Usually you don’t need the whole props
object itself, so you destructure it into individual props.
通常你不需要整个 props
对象,所以可以将它解构为单独的 props。
给 prop 指定一个默认值 | Specifying a default value for a prop
If you want to give a prop a default value to fall back on when no value is specified, you can do it with the destructuring by putting =
and the default value right after the parameter:
如果你想在没有指定值的情况下给 prop 一个默认值,你可以通过在参数后面写 =
和默认值来进行解构:
function Avatar({ person, size = 100 }) {
// ...
}
Now, if <Avatar person={...} />
is rendered with no size
prop, the size
will be set to 100
.
现在, 如果 <Avatar person={...} />
渲染时没有 size
prop, size
将被赋值为 100
。
The default value is only used if the size
prop is missing or if you pass size={undefined}
. But if you pass size={null}
or size={0}
, the default value will not be used.
默认值仅在缺少 size
prop 或 size={undefined}
时生效。 但是如果你传递了 size={null}
或 size={0}
,默认值将 不 被使用。
使用 JSX 展开语法传递 props | Forwarding props with the JSX spread syntax
Sometimes, passing props gets very repetitive: 有时候,传递 props 会变得非常重复:
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}
There’s nothing wrong with repetitive code—it can be more legible. But at times you may value conciseness. Some components forward all of their props to their children, like how this Profile
does with Avatar
. Because they don’t use any of their props directly, it can make sense to use a more concise “spread” syntax:
重复代码没有错(它可以更清晰)。但有时你可能会重视简洁。一些组件将它们所有的 props 转发给子组件,正如 Profile
转给 Avatar
那样。因为这些组件不直接使用他们本身的任何 props,所以使用更简洁的“展开”语法是有意义的:
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
This forwards all of Profile
’s props to the Avatar
without listing each of their names.
这会将 Profile
的所有 props 转发到 Avatar
,而不列出每个名字。
Use spread syntax with restraint. If you’re using it in every other component, something is wrong. Often, it indicates that you should split your components and pass children as JSX. More on that next! 请克制地使用展开语法。 如果你在所有其他组件中都使用它,那就有问题了。 通常,它表示你应该拆分组件,并将子组件作为 JSX 传递。 接下来会详细介绍!
将 JSX 作为子组件传递 | Passing JSX as children
It is common to nest built-in browser tags: 嵌套浏览器内置标签是很常见的:
<div>
<img />
</div>
Sometimes you’ll want to nest your own components the same way: 有时你会希望以相同的方式嵌套自己的组件:
<Card>
<Avatar />
</Card>
When you nest content inside a JSX tag, the parent component will receive that content in a prop called children
. For example, the Card
component below will receive a children
prop set to <Avatar />
and render it in a wrapper div:
当你将内容嵌套在 JSX 标签中时,父组件将在名为 children
的 prop 中接收到该内容。例如,下面的 Card
组件将接收一个被设为 <Avatar />
的 children
prop 并将其包裹在 div 中渲染:
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> ); }
Try replacing the <Avatar>
inside <Card>
with some text to see how the Card
component can wrap any nested content. It doesn’t need to “know” what’s being rendered inside of it. You will see this flexible pattern in many places.
尝试用一些文本替换 <Card>
中的 <Avatar>
,看看 Card
组件如何包裹任意嵌套内容。它不必“知道”其中渲染的内容。你会在很多地方看到这种灵活的模式。
You can think of a component with a children
prop as having a “hole” that can be “filled in” by its parent components with arbitrary JSX. You will often use the children
prop for visual wrappers: panels, grids, etc.
可以将带有 children
prop 的组件看作有一个“洞”,可以由其父组件使用任意 JSX 来“填充”。你会经常使用 children
prop 来进行视觉包装:面板、网格等等。
How props change over time | Props 如何随时间变化
The Clock
component below receives two props from its parent component: color
and time
. (The parent component’s code is omitted because it uses state, which we won’t dive into just yet.)
下面的 Clock
组件从其父组件接收两个 props:color
和 time
。(父组件的代码被省略,因为它使用 state,我们暂时不会深入研究。)
Try changing the color in the select box below: 尝试在下面的选择框中更改颜色:
export default function Clock({ color, time }) { return ( <h1 style={{ color: color }}> {time} </h1> ); }
This example illustrates that a component may receive different props over time. Props are not always static! Here, the time
prop changes every second, and the color
prop changes when you select another color. Props reflect a component’s data at any point in time, rather than only in the beginning.
这个例子说明,一个组件可能会随着时间的推移收到不同的 props。 Props 并不总是静态的!在这里,time
prop 每秒都在变化。当你选择另一种颜色时,color
prop 也改变了。Props 反映了组件在任何时间点的数据,并不仅仅是在开始时。
However, props are immutable—a term from computer science meaning “unchangeable”. When a component needs to change its props (for example, in response to a user interaction or new data), it will have to “ask” its parent component to pass it different props—a new object! Its old props will then be cast aside, and eventually the JavaScript engine will reclaim the memory taken by them. 然而,props 是 不可变的(一个计算机科学术语,意思是“不可改变”)。当一个组件需要改变它的 props(例如,响应用户交互或新数据)时,它不得不“请求”它的父组件传递 不同的 props —— 一个新对象!它的旧 props 将被丢弃,最终 JavaScript 引擎将回收它们占用的内存。
Don’t try to “change props”. When you need to respond to the user input (like changing the selected color), you will need to “set state”, which you can learn about in State: A Component’s Memory. 不要尝试“更改 props”。 当你需要响应用户输入(例如更改所选颜色)时,你可以“设置 state”,你可以在 State: 一个组件的内存 中继续了解。
摘要
- To pass props, add them to the JSX, just like you would with HTML attributes.
- 要传递 props,请将它们添加到 JSX,就像使用 HTML 属性一样。
- To read props, use the
function Avatar({ person, size })
destructuring syntax. - 要读取 props,请使用
function Avatar({ person, size })
解构语法。 - You can specify a default value like
size = 100
, which is used for missing andundefined
props. - 你可以指定一个默认值,如
size = 100
,用于缺少值或值为undefined
的 props 。 - You can forward all props with
<Avatar {...props} />
JSX spread syntax, but don’t overuse it! - 你可以使用
<Avatar {...props} />
JSX 展开语法转发所有 props,但不要过度使用它! - Nested JSX like
<Card><Avatar /></Card>
will appear asCard
component’schildren
prop. - 像
<Card><Avatar /></Card>
这样的嵌套 JSX,将被视为Card
组件的children
prop。 - Props are read-only snapshots in time: every render receives a new version of props.
- Props 是只读的时间快照:每次渲染都会收到新版本的 props。
- You can’t change props. When you need interactivity, you’ll need to set state.
- 你不能改变 props。当你需要交互性时,你可以设置 state。
第 1 个挑战 共 3 个挑战: 提取一个组件 | Extract a component
This Gallery
component contains some very similar markup for two profiles. Extract a Profile
component out of it to reduce the duplication. You’ll need to choose what props to pass to it.
这个 Gallery
组件包含两份个人资料,其中有一些非常相似的标签。从中提取一个 Profile
组件以减少重复。你需要选择要传递哪些 props。
import { getImageUrl } from './utils.js'; export default function Gallery() { return ( <div> <h1>Notable Scientists</h1> <section className="profile"> <h2>Maria Skłodowska-Curie</h2> <img className="avatar" src={getImageUrl('szV5sdG')} alt="Maria Skłodowska-Curie" width={70} height={70} /> <ul> <li> <b>Profession: </b> physicist and chemist </li> <li> <b>Awards: 4 </b> (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal) </li> <li> <b>Discovered: </b> polonium (chemical element) </li> </ul> </section> <section className="profile"> <h2>Katsuko Saruhashi</h2> <img className="avatar" src={getImageUrl('YfeOqp2')} alt="Katsuko Saruhashi" width={70} height={70} /> <ul> <li> <b>Profession: </b> geochemist </li> <li> <b>Awards: 2 </b> (Miyake Prize for geochemistry, Tanaka Prize) </li> <li> <b>Discovered: </b> a method for measuring carbon dioxide in seawater </li> </ul> </section> </div> ); }