快速入门

欢迎阅读 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>
  );
}

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

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

添加样式

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

<img className="avatar" />

然后,您在单独的 CSS 文件中编写 CSS 规则。

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

React 没有规定您如何添加 CSS 文件。在最简单的情况下,您将<link>标签添加到您的 HTML 中。如果您使用构建工具或框架,请查阅其文档以了解如何将 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 开头的函数称为 *Hook*。 useState 是 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 并将其传递给两个子组件。

现在,当您单击任一按钮时,MyApp 中的 count 将发生变化,这将更改 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 都设置为 MyApp 内部的 handleClick 函数,因此其中的代码将运行。该代码调用 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 构建您的第一个小型应用程序。