快速入门

欢迎来到 React 文档!本页面将向你介绍你在日常工作中会用到的 80% 的 React 概念。

你将学到

  • 如何创建和嵌套组件
  • 如何添加标记和样式
  • 如何显示数据
  • 如何渲染条件和列表
  • 如何响应事件并更新屏幕
  • 如何在组件之间共享数据

创建和嵌套组件

React 应用程序由组件构成。组件是 UI(用户界面)的一部分,它有自己的逻辑和外观。组件可以小到一个按钮,也可以大到整个页面。

React 组件是返回标记的 JavaScript 函数

function MyButton() {
return (
<button>I'm a button</button>
);
}

现在你已经声明了 MyButton,你可以将其嵌套到另一个组件中

export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}

注意,<MyButton /> 以大写字母开头。这就是你如何知道它是一个 React 组件。React 组件名称必须始终以大写字母开头,而 HTML 标签必须是小写。

看看结果

function MyButton() {
  return (
    <button>
      I'm a button
    </button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

export default 关键字指定了文件中的主组件。如果你不熟悉某些 JavaScript 语法,MDNjavascript.info 有很好的参考资料。

用 JSX 编写标记

你上面看到的标记语法称为JSX。它是可选的,但大多数 React 项目都使用 JSX,因为它很方便。我们推荐的所有本地开发工具都开箱即用地支持 JSX。

JSX 比 HTML 更加严格。你必须关闭像 <br /> 这样的标签。你的组件也不能返回多个 JSX 标签。你必须将它们包装到一个共享的父级中,例如 <div>...</div> 或一个空 <>...</> 包装器

function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}

如果你有很多 HTML 要移植到 JSX,可以使用在线转换器。

添加样式

在 React 中,你使用 className 指定 CSS 类。它的工作原理与 HTML class 属性相同

<img className="avatar" />

然后你将在一个单独的 CSS 文件中编写它的 CSS 规则

/* In your CSS */
.avatar {
border-radius: 50%;
}

React 并没有规定你如何添加 CSS 文件。在最简单的情况下,你将向你的 HTML 添加一个 <link> 标签。如果你使用构建工具或框架,请查看其文档以了解如何将 CSS 文件添加到项目中。

显示数据

JSX 让你可以将标记放入 JavaScript 中。花括号让你可以“逃回”到 JavaScript 中,这样你就可以嵌入代码中的一些变量并将其显示给用户。例如,这将显示 user.name

return (
<h1>
{user.name}
</h1>
);

你也可以从 JSX 属性中“逃回 JavaScript”,但你必须使用花括号而不是引号。例如,className="avatar""avatar" 字符串作为 CSS 类传递,但 src={user.imageUrl} 读取 JavaScript user.imageUrl 变量值,然后将该值作为 src 属性传递

return (
<img
className="avatar"
src={user.imageUrl}
/>
);

你也可以在 JSX 花括号中放置更复杂的表达式,例如 字符串连接

const user = {
  name: 'Hedy Lamarr',
  imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
  imageSize: 90,
};

export default function Profile() {
  return (
    <>
      <h1>{user.name}</h1>
      <img
        className="avatar"
        src={user.imageUrl}
        alt={'Photo of ' + user.name}
        style={{
          width: user.imageSize,
          height: user.imageSize
        }}
      />
    </>
  );
}

在上面的示例中,style={{}} 不是特殊的语法,而是在 style={ } JSX 花括号内的普通 {} 对象。当你的样式依赖于 JavaScript 变量时,可以使用 style 属性。

条件渲染

在 React 中,没有专门的语法来编写条件。相反,你将使用与编写常规 JavaScript 代码时相同的技术。例如,你可以使用 if 语句有条件地包含 JSX。

let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);

如果你更喜欢更紧凑的代码,你可以使用 条件 ? 运算符。if 不同,它在 JSX 中有效。

<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>

当你不需要 else 分支时,你也可以使用更短的 逻辑 && 语法。

<div>
{isLoggedIn && <AdminPanel />}
</div>

所有这些方法也适用于有条件地指定属性。如果你不熟悉其中的一些 JavaScript 语法,你可以从始终使用 if...else 开始。

渲染列表

你将依赖于 JavaScript 功能,例如 for 循环数组 map() 函数 来渲染组件列表。

例如,假设你有一个产品数组

const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];

在你的组件中,使用 map() 函数将产品数组转换为 <li> 项数组。

const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);

return (
<ul>{listItems}</ul>
);

请注意,<li> 具有 key 属性。对于列表中的每个项目,你应该传递一个字符串或数字,该字符串或数字在兄弟姐妹中唯一地标识该项目。通常,键应该来自你的数据,例如数据库 ID。React 使用你的键来了解你稍后插入、删除或重新排序项目时发生了什么。

const products = [
  { title: 'Cabbage', isFruit: false, id: 1 },
  { title: 'Garlic', isFruit: false, id: 2 },
  { title: 'Apple', isFruit: true, id: 3 },
];

export default function ShoppingList() {
  const listItems = products.map(product =>
    <li
      key={product.id}
      style={{
        color: product.isFruit ? 'magenta' : 'darkgreen'
      }}
    >
      {product.title}
    </li>
  );

  return (
    <ul>{listItems}</ul>
  );
}

响应事件

你可以通过在组件中声明事件处理程序函数来响应事件。

function MyButton() {
function handleClick() {
alert('You clicked me!');
}

return (
<button onClick={handleClick}>
Click me
</button>
);
}

请注意,onClick={handleClick} 末尾没有括号!不要调用事件处理程序函数:你只需要传递它。当用户点击按钮时,React 将调用你的事件处理程序。

更新屏幕

通常,你希望你的组件“记住”一些信息并显示它。例如,也许你想计算按钮被点击的次数。为此,请向你的组件添加状态

首先,从 React 中导入 useState

import { useState } from 'react';

现在,你可以在组件中声明一个状态变量

function MyButton() {
const [count, setCount] = useState(0);
// ...

你将从 useState 中得到两件事:当前状态 (count) 以及允许你更新它的函数 (setCount)。你可以给他们任何名字,但惯例是写 [something, setSomething]

按钮第一次显示时,count 将为 0,因为你将 0 传递给了 useState()。当你想更改状态时,请调用 setCount() 并将新值传递给它。点击此按钮将增加计数器。

function MyButton() {
const [count, setCount] = useState(0);

function handleClick() {
setCount(count + 1);
}

return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}

React 将再次调用你的组件函数。这次,count 将为 1。然后它将为 2。等等。

如果你多次渲染同一个组件,每个组件都将获得自己的状态。分别点击每个按钮。

import { useState } from 'react';

export default function MyApp() {
  return (
    <div>
      <h1>Counters that update separately</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

请注意,每个按钮如何“记住”它自己的 count 状态,并且不会影响其他按钮。

使用 Hook

use 开头的函数称为HookuseState 是 React 提供的内置 Hook。你可以在 API 参考 中找到其他内置 Hook。你还可以通过组合现有的 Hook 来编写自己的 Hook。

Hook 比其他函数更严格。你只能在组件(或其他 Hook)的顶部调用 Hook。如果你想在条件或循环中使用 useState,请提取一个新的组件并将其放在那里。

组件之间的数据共享

在前面的例子中,每个 MyButton 都有自己独立的 count,当每个按钮被点击时,只有被点击的按钮的 count 会发生变化

Diagram showing a tree of three components, one parent labeled MyApp and two children labeled MyButton. Both MyButton components contain a count with value zero.
Diagram showing a tree of three components, one parent labeled MyApp and two children labeled MyButton. Both MyButton components contain a count with value zero.

最初,每个 MyButtoncount 状态是 0

The same diagram as the previous, with the count of the first child MyButton component highlighted indicating a click with the count value incremented to one. The second MyButton component still contains value zero.
The same diagram as the previous, with the count of the first child MyButton component highlighted indicating a click with the count value incremented to one. The second MyButton component still contains value zero.

第一个 MyButton 将其 count 更新为 1

但是,通常您需要组件来 _共享数据并始终一起更新_。

要使两个 MyButton 组件显示相同的 count 并一起更新,您需要将状态从单个按钮 “向上” 移动到包含所有按钮的最近的组件。

在这个例子中,它是 MyApp

Diagram showing a tree of three components, one parent labeled MyApp and two children labeled MyButton. MyApp contains a count value of zero which is passed down to both of the MyButton components, which also show value zero.
Diagram showing a tree of three components, one parent labeled MyApp and two children labeled MyButton. MyApp contains a count value of zero which is passed down to both of the MyButton components, which also show value zero.

最初,MyAppcount 状态是 0,并传递给两个子组件

The same diagram as the previous, with the count of the parent MyApp component highlighted indicating a click with the value incremented to one. The flow to both of the children MyButton components is also highlighted, and the count value in each child is set to one indicating the value was passed down.
The same diagram as the previous, with the count of the parent MyApp component highlighted indicating a click with the value incremented to one. The flow to both of the children MyButton components is also highlighted, and the count value in each child is set to one indicating the value was passed down.

单击时,MyApp 将其 count 状态更新为 1,并将其传递给两个子组件

现在,当您单击任一按钮时,countMyApp 中将发生改变,这将改变两个 MyButton 中的计数。以下是您如何在代码中表达这一点。

首先,_将状态向上_ 从 MyButton 移动到 MyApp

export default function MyApp() {
const [count, setCount] = useState(0);

function handleClick() {
setCount(count + 1);
}

return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}

function MyButton() {
// ... we're moving code from here ...
}

然后,_将状态向下_ 从 MyApp 传递到每个 MyButton,以及共享的点击处理程序。您可以使用 JSX 花括号将信息传递给 MyButton,就像您之前对 <img> 等内置标签所做的那样

export default function MyApp() {
const [count, setCount] = useState(0);

function handleClick() {
setCount(count + 1);
}

return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}

您像这样传递下去的信息被称为 _props_。现在,MyApp 组件包含 count 状态和 handleClick 事件处理程序,并 _将它们都作为 props 传递给_ 每个按钮。

最后,更改 MyButton 来 _读取_ 您从其父组件传递的 props

function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}

当您单击按钮时,onClick 处理程序会触发。每个按钮的 onClick prop 都设置为 handleClick 函数,该函数位于 MyApp 中,因此其中的代码会运行。该代码调用 setCount(count + 1),从而递增 count 状态变量。新的 count 值作为 prop 传递给每个按钮,因此它们都显示新值。这称为 “将状态向上提升”。通过将状态向上移动,您已在组件之间共享了它。

import { useState } from 'react';

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update together</h1>
      <MyButton count={count} onClick={handleClick} />
      <MyButton count={count} onClick={handleClick} />
    </div>
  );
}

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </button>
  );
}

下一步

到目前为止,您已经了解了如何编写 React 代码的基本知识!

查看 教程 将它们付诸实践,并使用 React 构建您的第一个迷你应用程序。