v19.2Latest

向组件传递 Props

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

您将学习
  • 如何向组件传递 props
  • 如何从组件读取 props
  • 如何为 props 指定默认值
  • 如何向组件传递一些 JSX
  • Props 如何随时间变化

熟悉的 props

Props 是你传递给 JSX 标签的信息。例如,classNamesrcaltwidthheight 是你可以传递给 <img>的一些 props:

你可以传递给 <img>标签的 props 是预定义的(ReactDOM 遵循HTML 标准)。但你可以向 你自己的组件传递任何 props,例如<Avatar>,以自定义它们。方法如下!

向组件传递 props

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

你可以通过两个步骤给Avatar传递一些 props。

步骤 1:向子组件传递 props

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

注意

如果 person=后面的双花括号让你困惑,请回想它们仅仅是 JSX 花括号内的一个对象

现在你可以在 Avatar组件内部读取这些 props。

步骤 2:在子组件内部读取 props

你可以通过在 function Avatar之后直接列出它们的名称person, size(用逗号分隔)并放在({})中来读取这些 props。这让你可以在Avatar代码内部使用它们,就像使用变量一样。

Avatar添加一些使用personsizeprops 进行渲染的逻辑,你就完成了。

现在你可以通过不同的 props 来配置Avatar,使其以多种不同的方式渲染。尝试调整这些值!

Props 让你可以独立地思考父组件和子组件。例如,你可以在 Profile内部更改personsizeprops,而无需考虑Avatar如何使用它们。同样,你也可以更改Avatar如何使用这些 props,而无需查看Profile

你可以将 props 视为可以调整的“旋钮”。它们的作用与函数参数的作用相同——事实上,props就是你组件的唯一参数!React 组件函数接受一个参数,即一个props对象:

通常你不需要整个 props对象本身,因此你可以将其解构为单独的 props。

陷阱

不要遗漏 {}这对花括号,它们位于声明 props 时的() 内部:

这种语法称为 “解构”,等同于从函数参数中读取属性:

为 prop 指定默认值

如果你想为 prop 指定一个默认值,以便在未指定值时回退使用,可以通过在参数后放置= 和默认值来进行解构:

现在,如果渲染<Avatar person={...} /> 时没有 sizeprop,size将被设置为100

默认值仅在 sizeprop 缺失或你传递size={undefined}时使用。但如果你传递size={null}size={0},默认值将 不会被使用。

使用 JSX 展开语法传递 props

有时,传递 props 会变得非常重复:

重复的代码本身没有问题——它可能更具可读性。但有时你可能更看重简洁性。有些组件会将其所有 props 传递给它们的子组件,就像这个Profile 组件对 Avatar所做的那样。因为它们不直接使用任何 props,所以使用更简洁的“展开”语法可能更有意义:

这将 Profile的所有 props 传递给Avatar,而无需逐一列出它们的名称。

请谨慎使用展开语法。如果你在每个其他组件中都使用它,那可能有问题。通常,这表明你应该拆分组件并将子组件作为 JSX 传递。接下来会详细介绍!

将 JSX 作为子组件传递

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

有时你会希望以同样的方式嵌套你自己的组件:

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

尝试将 <Avatar>替换为一些文本,看看<Card>组件如何包装任何嵌套内容。它不需要“知道”内部渲染的是什么。你会在许多地方看到这种灵活的模式。

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

一个类似拼图的 Card 方块,带有用于“children”片段的插槽,如文本和 Avatar

插图由Rachel Lee Nabors

Props 如何随时间变化

下面的Clock 组件从其父组件接收两个 props:colortime。(父组件的代码被省略了,因为它使用了state,我们暂时不会深入探讨。)

尝试在下面的选择框中更改颜色:

这个例子说明了 组件可能会随时间接收不同的 props。Props 并不总是静态的!在这里,timeprop 每秒变化一次,而colorprop 在你选择另一种颜色时变化。Props 反映了组件在任何时间点的数据,而不仅仅是在开始时。

然而,props 是不可变的——这是一个来自计算机科学的术语,意思是“不可更改”。当组件需要更改其 props 时(例如,响应用户交互或新数据),它必须“请求”其父组件传递不同的 props——一个新的对象!然后它的旧 props 将被丢弃,最终 JavaScript 引擎将回收它们占用的内存。

不要尝试“更改 props”。 当你需要响应用户输入(例如更改所选颜色)时,你将需要“设置状态”,你可以在 State: A Component’s Memory 中学习。

回顾

  • 要传递 props,请将它们添加到 JSX 中,就像处理 HTML 属性一样。
  • 要读取 props,请使用function Avatar({ person, size }) 解构语法。
  • 你可以指定一个默认值,例如size = 100,它用于缺失和 undefined的 props。
  • 你可以使用 <Avatar {...props} />JSX 展开语法转发所有 props,但不要过度使用它!
  • 嵌套的 JSX,如<Card><Avatar /></Card> 将作为 Card 组件的 childrenprop 出现。
  • props 是只读的时间快照:每次渲染都会接收到一个新版本的 props。
  • 你不能更改 props。当你需要交互性时,你需要设置状态。

Try out some challenges

Challenge 1 of 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.