使用 Props 展示数据

到目前为止,如果你要复用 <Header /> 组件,两次显示的内容会是相同的。

index.html
function Header() {
  return <h1>Develop. Preview. Ship.</h1>;
}
 
function HomePage() {
  return (
    <div>
      <Header />
      <Header />
    </div>
  );
}

但如果你想传递不同的文本,或者由于数据来自外部源而无法提前获知信息,该怎么办呢?

常规 HTML 元素具有属性,可以用来传递信息片段以改变元素的行为。例如,修改 <img> 元素的 src 属性会改变显示的图片,修改 <a> 标签的 href 属性会改变链接的目标。

同样地,你可以将信息片段作为属性传递给 React 组件,这些属性称为 props。以按钮组件的几种可能变体为例:

展示按钮组件的三种变体:主要按钮、次要按钮和禁用按钮的示意图

类似于 JavaScript 函数,你可以设计接受自定义参数(或 props)的组件,这些参数会改变组件的行为或在渲染到屏幕上时显示的内容。然后,你可以将这些 props 从父组件传递到子组件。

注意: 在 React 中,数据沿组件树向下流动,这被称为 单向数据流。状态(将在下一章讨论)可以作为 props 从父组件传递到子组件。

使用 props

HomePage 组件中,你可以像传递 HTML 属性一样,向 Header 组件传递一个自定义的 title prop:

index.html
function HomePage() {
  return (
    <div>
      <Header title="React" />
    </div>
  );
}

而子组件 Header 可以通过其第一个函数参数接收这些 props:

index.html
function Header(props) {
  return <h1>Develop. Preview. Ship.</h1>;
}

如果你调用 console.log() 打印 props,会发现它是一个包含 title 属性的对象

index.html
function Header(props) {
  console.log(props); // { title: "React" }
  return <h1>Develop. Preview. Ship.</h1>;
}

由于 props 是一个对象,你可以在函数参数中使用对象解构来显式命名 props 的值:

index.html
function Header({ title }) {
  console.log(title); // "React"
  return <h1>Develop. Preview. Ship.</h1>;
}

然后,你可以将 <h1> 标签的内容替换为你的 title 变量。

index.html
function Header({ title }) {
  console.log(title);
  return <h1>title</h1>;
}

如果你在浏览器中打开文件,会发现它显示的是字符串 "title"。这是因为 React 认为你打算向 DOM 渲染纯文本字符串。

你需要一种方式告诉 React 这是一个 JavaScript 变量。

在 JSX 中使用变量

要使用 title prop,可以添加花括号 {}。这是一种特殊的 JSX 语法,允许你在 JSX 标记中直接编写常规 JavaScript。

index.html
function Header({ title }) {
  console.log(title);
  return <h1>{title}</h1>;
}

你可以将花括号视为从 "JSX 世界" 进入 "JavaScript 世界" 的入口。你可以在花括号中添加任何JavaScript 表达式(即能求值为单个值的代码)。例如:

  1. 对象属性的点表示法:
example.js
function Header(props) {
  return <h1>{props.title}</h1>;
}
  1. 模板字符串
example.js
function Header({ title }) {
  return <h1>{`Cool ${title}`}</h1>;
}
  1. 函数的返回值
example.js
function createTitle(title) {
  if (title) {
    return title;
  } else {
    return 'Default title';
  }
}
 
function Header({ title }) {
  return <h1>{createTitle(title)}</h1>;
}
  1. 三元运算符
example.js
function Header({ title }) {
  return <h1>{title ? title : 'Default Title'}</h1>;
}

现在,你可以向 title prop 传递任何字符串。如果使用了三元运算符,甚至可以不传递 title prop,因为组件中已经处理了默认情况:

example.js
function Header({ title }) {
  return <h1>{title ? title : 'Default title'}</h1>;
}
 
function HomePage() {
  return (
    <div>
      <Header />
    </div>
  );
}

你的组件现在接受一个通用的 title prop,可以在应用的不同部分复用。只需更改传递的字符串即可:

index.html
function HomePage() {
  return (
    <div>
      <Header title="React" />
      <Header title="A new title" />
    </div>
  );
}

遍历列表

通常会有需要以列表形式展示的数据。你可以使用数组方法来操作数据,并生成样式相同但包含不同信息的 UI 元素。

将以下名字数组添加到 HomePage 组件中:

index.html
function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li>{name}</li>
        ))}
      </ul>
    </div>
  );
}

然后,可以使用 array.map() 方法遍历数组,并通过箭头函数将每个名字映射为一个列表项:

index.html
function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li>{name}</li>
        ))}
      </ul>
    </div>
  );
}

注意你是如何使用花括号在 "JavaScript" 和 "JSX" 世界之间切换的。

如果运行这段代码,React 会警告缺少 key prop。这是因为 React 需要唯一标识数组中的元素,以便知道需要更新 DOM 中的哪些元素。

目前可以使用名字作为唯一标识,但建议使用保证唯一的值,比如项目 ID。

index.html
function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>
    </div>
  );
}

额外资源:

On this page