介绍 react.dev

2023 年 3 月 16 日,Dan AbramovRachel Nabors


今天,我们很高兴地宣布 react.dev 正式发布,它是 React 及其文档的新家园。在这篇文章中,我们将带你参观一下这个新网站。


tl;dr

  • 新的 React 网站(react.dev)使用函数组件和 Hooks 教你现代 React。
  • 我们添加了图表、插图、挑战和超过 600 个新的交互式示例。
  • 之前的 React 文档网站已迁移至 legacy.reactjs.org

新网站、新域名、新首页

首先,先来做一些说明。

为了庆祝新文档的发布,更重要的是,为了清晰地将旧内容和新内容区分开来,我们启用了更简短的 react.dev 域名。旧的 reactjs.org 域名现在将重定向到这里。

旧的 React 文档现在已归档到 legacy.reactjs.org。所有指向旧内容的现有链接都将自动重定向到那里,以避免“破坏网络”,但旧网站不会再进行太多更新。

信不信由你,React 很快就要十岁了。用 JavaScript 年来算,这就像整整一个世纪!我们刷新了 React 主页,以反映我们认为 React 是当今创建用户界面的绝佳方式,并更新了入门指南,以更突出地提及现代的基于 React 的框架。

如果你还没有看过新主页,快去看看吧!

全面拥抱使用 Hooks 的现代 React

当我们在 2018 年发布 React Hooks 时,Hooks 文档假设读者熟悉类组件。这帮助社区非常迅速地采用了 Hooks,但一段时间后,旧文档就无法再为新读者服务了。新读者不得不学习 React 两遍:一遍是使用类组件,然后一遍是使用 Hooks。

新文档从一开始就使用 Hooks 教你 React。 文档分为两个主要部分

  • 学习 React 是一门自学课程,从零开始教你 React。
  • API 参考 提供了每个 React API 的详细信息和用法示例。

让我们仔细看看每个部分的内容。

注意

仍然有一些罕见的类组件用例还没有基于 Hook 的等效项。类组件仍然受支持,并在新网站的 Legacy API 部分中进行了介绍。

快速入门

“学习”部分从 快速入门 页面开始。这是一个简短的 React 介绍性教程。它介绍了组件、props 和状态等概念的语法,但没有详细介绍如何使用它们。

如果你喜欢边做边学,我们建议你接下来查看 井字棋教程。它将引导你使用 React 构建一个小游戏,同时教你每天都会用到的技能。以下是你要构建的内容

import { useState } from 'react';

function Square({ value, onSquareClick }) {
  return (
    <button className="square" onClick={onSquareClick}>
      {value}
    </button>
  );
}

function Board({ xIsNext, squares, onPlay }) {
  function handleClick(i) {
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    const nextSquares = squares.slice();
    if (xIsNext) {
      nextSquares[i] = 'X';
    } else {
      nextSquares[i] = 'O';
    }
    onPlay(nextSquares);
  }

  const winner = calculateWinner(squares);
  let status;
  if (winner) {
    status = 'Winner: ' + winner;
  } else {
    status = 'Next player: ' + (xIsNext ? 'X' : 'O');
  }

  return (
    <>
      <div className="status">{status}</div>
      <div className="board-row">
        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />
        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />
        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />
      </div>
      <div className="board-row">
        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />
        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />
        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />
      </div>
      <div className="board-row">
        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />
        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />
        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />
      </div>
    </>
  );
}

export default function Game() {
  const [history, setHistory] = useState([Array(9).fill(null)]);
  const [currentMove, setCurrentMove] = useState(0);
  const xIsNext = currentMove % 2 === 0;
  const currentSquares = history[currentMove];

  function handlePlay(nextSquares) {
    const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];
    setHistory(nextHistory);
    setCurrentMove(nextHistory.length - 1);
  }

  function jumpTo(nextMove) {
    setCurrentMove(nextMove);
  }

  const moves = history.map((squares, move) => {
    let description;
    if (move > 0) {
      description = 'Go to move #' + move;
    } else {
      description = 'Go to game start';
    }
    return (
      <li key={move}>
        <button onClick={() => jumpTo(move)}>{description}</button>
      </li>
    );
  });

  return (
    <div className="game">
      <div className="game-board">
        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />
      </div>
      <div className="game-info">
        <ol>{moves}</ol>
      </div>
    </div>
  );
}

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

我们还想重点介绍一下 React 思维——这个教程让很多人“顿悟”了 React。我们更新了这两个经典教程,以使用函数组件和 Hooks,因此它们焕然一新。

注意

上面的例子是一个沙盒。我们在整个网站中添加了许多沙盒——超过 600 个!你可以编辑任何沙盒,或点击右上角的“分支”按钮,在新标签页中打开它。沙盒可以让你快速玩转 React API,探索你的想法,并检查你的理解。

一步一步学习 React

我们希望世界上每个人都有平等的机会免费自学 React。

这就是为什么“学习”部分被组织成一个自学课程,分为多个章节。前两章描述了 React 的基础知识。如果你是 React 新手,或者想温习一下,请从这里开始

  • 描述 UI 教你如何使用组件显示信息。
  • 添加交互 教你如何根据用户输入更新屏幕。

接下来的两章更加进阶,将带你深入了解 React 中更棘手的部分。

  • 管理状态 教你如何在应用复杂度增加时组织逻辑。
  • 逃生舱 教你如何在需要时“跳出”React,以及何时这样做最合理。

每一章都包含若干相关的页面。大多数页面教授特定的技能或技巧——例如,使用 JSX 编写标记更新状态中的对象在组件之间共享状态。有些页面侧重于解释概念——例如渲染和提交状态快照。还有一些页面,例如你可能不需要 Effect,分享了我们多年来学习到的一些建议。

你不需要按顺序阅读这些章节。谁有时间这样做?!但你可以这样做。“学习”部分的页面只依赖于前面页面介绍的概念。如果你想像读书一样阅读,那就去吧!

通过挑战来检验你的理解

“学习”部分的大多数页面都以一些挑战结束,以检验你的理解。例如,以下是关于条件渲染页面中的一些挑战。

你不必现在就解决它们!除非你真的想这样做。

挑战 1 2:
使用? :显示未完成项目的图标。

如果isPacked不是true,则使用条件运算符(cond ? a : b)渲染❌。

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

注意左下角的“显示解决方案”按钮。如果你想检查自己的答案,它会很方便!

通过图表和插图建立直觉

当我们无法仅用代码和文字解释清楚某些内容时,我们添加了图表来帮助你建立直觉。例如,以下是保留和重置状态中的一个图表。

Diagram with three sections, with an arrow transitioning each section in between. The first section contains a React component labeled 'div' with a single child labeled 'section', which has a single child labeled 'Counter' containing a state bubble labeled 'count' with value 3. The middle section has the same 'div' parent, but the child components have now been deleted, indicated by a yellow 'proof' image. The third section has the same 'div' parent again, now with a new child labeled 'div', highlighted in yellow, also with a new child labeled 'Counter' containing a state bubble labeled 'count' with value 0, all highlighted in yellow.
Diagram with three sections, with an arrow transitioning each section in between. The first section contains a React component labeled 'div' with a single child labeled 'section', which has a single child labeled 'Counter' containing a state bubble labeled 'count' with value 3. The middle section has the same 'div' parent, but the child components have now been deleted, indicated by a yellow 'proof' image. The third section has the same 'div' parent again, now with a new child labeled 'div', highlighted in yellow, also with a new child labeled 'Counter' containing a state bubble labeled 'count' with value 0, all highlighted in yellow.

section更改为div时,section被删除,并添加了新的div

你还将在文档中看到一些插图——以下是浏览器绘制屏幕的插图之一。

A browser painting 'still life with card element'.

插图作者: Rachel Lee Nabors

我们已与浏览器供应商确认,此图示 100% 科学准确。

全新的、详细的 API 参考

API 参考中,每个 React API 现在都有一个专门的页面。这包括所有类型的 API:

你会注意到,每个 API 页面都至少分为两部分:参考用法

参考通过列出 API 的参数和返回值来描述其形式上的签名。它很简洁,但如果你不熟悉该 API,可能会觉得有点抽象。它描述了 API 的功能,但没有说明如何使用它。

用法” 部分会像你的同事或朋友一样,解释为何以及如何在实践中使用此 API。它展示了 React 团队希望每个 API 如何使用的规范场景。 我们添加了颜色编码的代码片段、一起使用不同 API 的示例,以及你可以直接复制粘贴的代码配方。

基本的 useState 示例

示例 1 4:
计数器(数字)

在此示例中,count 状态变量保存一个数字。点击按钮会递增它。

import { useState } from 'react';

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

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

  return (
    <button onClick={handleClick}>
      You pressed me {count} times
    </button>
  );
}

某些 API 页面还包括 故障排除(针对常见问题)和 替代方案(针对已弃用 API)。

我们希望这种方法不仅可以使 API 参考成为一种查找参数的方式,而且可以成为一种查看可以使用任何给定 API 执行的所有不同操作以及它如何与其他 API 连接的方式。

下一步是什么?

我们的简短介绍到此结束!浏览一下新网站,看看你喜欢或不喜欢什么,并在我们的 问题跟踪器 中持续提供反馈。

我们承认这个项目花了很长时间才发布。我们希望保持 React 社区应得的高质量标准。在编写这些文档和创建所有示例时,我们发现了一些解释中的错误、React 中的错误,甚至是 React 设计中的缺陷,我们现在正在努力解决这些问题。我们希望新的文档能帮助我们在未来将 React 本身提升到更高的标准。

我们听到了许多关于扩展网站内容和功能的请求,例如

  • 为所有示例提供 TypeScript 版本;
  • 创建更新的性能、测试和可访问性指南;
  • 独立于支持 React 服务器组件的框架记录它们;
  • 与我们的国际社区合作翻译新文档;
  • 为新网站添加缺失的功能(例如,此博客的 RSS)。

现在 react.dev 已经发布,我们将能够将重点从“赶上”第三方 React 教育资源转移到添加新信息和进一步改进我们的新网站。

我们认为现在是学习 React 的最佳时机。

谁参与了这项工作?

在 React 团队中,Rachel Nabors 领导了该项目(并提供了插图),Dan Abramov 设计了课程。他们还共同撰写了大部分内容。

当然,像这样的大型项目不可能孤立地完成。我们要感谢很多人!

Sylwia Vargas 改进了我们的示例,使其超越了“foo/bar/baz”和小猫,而是以来自世界各地的科学家、艺术家和城市为特色。Maggie Appleton 将我们的涂鸦变成了清晰的图表系统。

感谢 David McCabeSophie AlpertRick HanlonAndrew ClarkMatt Carroll 对写作的额外贡献。我们还要感谢 Natalia TepluhinaSebastian Markbåge 的想法和反馈。

感谢 Dan Lebowitz 的网站设计和 Razvan Gradinar 的沙盒设计。

在开发方面,感谢 Jared Palmer 的原型开发。感谢来自 ThisDotLabsDane GrantDustin Goodman 对 UI 开发的支持。感谢来自 CodeSandboxIves van HoorneAlex MoldovanJasper De MoorDanilo Woznica 对沙盒集成的贡献。感谢 Rick Hanlon 在现场开发和设计方面的工作,完善了我们的颜色和更精细的细节。感谢 Harish KumarLuna Ruan 为网站添加新功能并帮助维护它。

非常感谢那些自愿抽出时间参与 Alpha 和 Beta 测试计划的人们。你们的热情和宝贵的反馈帮助我们塑造了这些文档。特别感谢我们的 Beta 测试员,Debbie O’Brien,她在 2021 年 React 大会上发表了关于她使用 React 文档的经验的演讲。

最后,感谢 React 社区为这项工作带来的启发。你们是我们这样做的原因,我们希望新的文档能够帮助你们使用 React 构建任何你们想要的界面。