介绍 react.dev

2023 年 3 月 16 日 Dan Abramov 与 Rachel Nabors


今天,我们非常高兴推出 react.dev,React 及其文档的新家。在本文中,我们想带你参观新网站。


tl;dr

  • 新的 React 文档网站(react.dev)将介绍使用函数式组件和 Hook 的现代 React。
  • 新网站包括了图表、插图、挑战和超过 600 个新的交互式示例。
  • 旧的 React 文档网站现在已经迁移到 legacy.reactjs.org。

新网站,新域名,新主页

首先,介绍一些小的背景。

为了庆祝新文档的发布,更重要的是为了清晰区分新旧内容,我们已经将域名更改为更短的 react.dev;旧的 reactjs.org 域名现在将重定向到此处。

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

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

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

进入使用 Hook 的现代 React

当 React 在 2018 年发布 Hook 时,Hook 文档假定读者熟悉类组件。这有助于社区非常迅速地采用 Hook,但是一段时间后,旧的文档无法为新读者服务,因为新读者不得不学习两次 React:一次是使用类式组件,然后再学习在函数式组件中使用 Hook。

新文档从一开始就使用 Hook 来介绍 React。新文档分为两个主要部分:

  • 学习 React 是一个自学课程,从头开始介绍 React。
  • API 参考 提供了每个 React API 的详细信息和使用示例。

让我们更仔细地看看可以从每个部分中找到什么。

注意

仍有一些罕见的类式组件尚未有基于 Hook 的替代品。React 仍然支持类式组件,并且在新网站的 legacy API 部分中有文档记录。

快速入门

学习部分从 快速入门 页面开始。它是 React 的一个简短介绍性导览,介绍了诸如组件、props 和 state 等概念,但并不详细介绍如何使用它们。

如果你喜欢通过实践来学习,我们建议你接下来查看 井字棋教程。它会带领你一步步构建一个小游戏,同时介绍你每天都会用到的技能。这是你将要构建的内容:

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 的教程。我们使用了函数式组件和 Hook 更新了这两个经典教程。

注意

上面的例子使用了 sandbox。我们在整个网站上添加了超过 600 个 sandbox。你可以编辑所有的 sandbox,或者点击右上角的 Fork 按钮,然后在单独的标签页中打开它。sandbox 可以让你快速体验 React API,探索你的想法并检查你的理解。

一步步学习 React

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

这就是为什么“学习”部分被组织成一个自学课程的章节。前两章描述了 React 的基本知识。如果你是初次尝试 React,或者想要刷新你对 React 的记忆,可以从这里开始:

  • 描述 UI 章节介绍了如何使用组件显示信息。
  • 添加交互性 章节介绍了如何在响应用户输入时更新屏幕。

接下来的两章持续深入,将带你了解更棘手的部分:

  • 管理状态 章节介绍了如何在应用程序变得越来越复杂时组织逻辑。
  • 脱围机制 章节介绍了如何“走出”React,并在何时做出最明智的决策。

每个章节都由几个相关的页面组成。其中大部分页面将介绍特定的技能或技术,例如 使用 JSX 编写标记、更新状态中的对象 或 在组件间共享状态。一些页面聚焦于解释一个概念,例如 渲染和提交 或 将状态作为快照(snapshot)。还有一些页面如 你可能不需要 Effect 是基于我们多年的经验而分享的建议。

你不必完全按顺序阅读这些章节,谁有这个时间呢?!不过也许你可以。学习部分的页面只依赖于早期页面介绍的概念。如果你想像读书一样阅读它,那就去吧!

使用挑战(challenge)检查你的理解

“学习”章节的大多数页面都以一些挑战结尾,以检查你的理解情况。例如以下是有关 条件渲染 页面上的一些挑战。

除非你真的如此想,不然不必现在就解决它们!

第 1 个挑战 共 2 个挑战:
使用 ? : 显示不完整 item 的图标

如果 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>
  );
}

请注意左下角的“显示解决方案”按钮。如果你想要检查自己的代码,它会很有用!

通过图表和插图来建立直觉

当我们无法弄清楚如何仅用代码和文字来解释某些内容时,我们添加了有助于提供一些直觉的图表。例如,下面是 保存和重置 state 中的图表之一:

图表包含三个部分,每个部分之间有一个箭头过渡。 第一部分包含一个标记为 `div` 的 React 组件,其中有一个标记为 `section` 的子组件,该组件有一个标记为 `Counter` 的子组件,其中包含一个标记为 `count`、值为 3 的 state 气泡。中间部分具有相同的 `div` 父组件,但子组件现已被删除,由黄色“proof”图像指示。第三部分再次具有相同的 `div` 父级,现在有一个由黄色突出显示并且标记为 `div` 的新子级,还有一个标记为 `Counter` 的新子级,其中包含一个标记为 `count` 且值为 0 的 state 气泡。她们都使用黄色进行了高亮。
图表包含三个部分,每个部分之间有一个箭头过渡。 第一部分包含一个标记为 `div` 的 React 组件,其中有一个标记为 `section` 的子组件,该组件有一个标记为 `Counter` 的子组件,其中包含一个标记为 `count`、值为 3 的 state 气泡。中间部分具有相同的 `div` 父组件,但子组件现已被删除,由黄色“proof”图像指示。第三部分再次具有相同的 `div` 父级,现在有一个由黄色突出显示并且标记为 `div` 的新子级,还有一个标记为 `Counter` 的新子级,其中包含一个标记为 `count` 且值为 0 的 state 气泡。她们都使用黄色进行了高亮。

当 section 被改变为 div 时,section 会被删除而新的 div 会被添加。

在文档中还有一些插图——这是其中一个 浏览器绘制屏幕的示意图。

我们已经与浏览器厂商确认,这个描绘是 100% 科学准确的。

新的并且更细致的 API 参考

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

你会注意到,每个 API 页面至少被分成两个部分:参考 和 用法。

参考 通过列举参数与返回值描述了正式的 API。这一部分比较简洁,但如果你不熟悉该 API,你可能会感觉有点抽象。“参考”描述了一个 API 做什么,但不是如何使用它。

用法 展示了为什么需要以及如何在实践中使用这个 API,就像同事或朋友可能会解释的那样。它展示了 React 团队设计每个 API 的 典型使用场景。我们添加了彩色代码片段、使用不同 API 的示例以及可以复制和粘贴的示例。

useState 的基础示例

第 1 个示例 共 4 个示例:
数字计数

在这个例子中,count state 变量保存了一个数字。点击按钮会将其递增。

import { useState } from 'react';

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

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

  return (
    <button onClick={handleClick}>
      你点击了 {count} 次
    </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”、kitten,和来自世界各地的科学家、艺术家和城市。Maggie Appleton 将我们的涂鸦转化成了清晰的图表系统。

感谢 David McCabe、Sophie Alpert、Rick Hanlon、Andrew Clark 和 Matt Carroll 提供额外的写作贡献。我们还要感谢 Natalia Tepluhina 和 Sebastian Markbåge 提供的想法和反馈。

感谢 Dan Lebowitz 设计了网站,Razvan Gradinar 设计了 sandbox。

在开发方面,感谢 Jared Palmer 进行原型开发。感谢 Dane Grant 和来自 ThisDotLabs 的 Dustin Goodman 为 UI 开发提供了支持。感谢 Ives van Hoorne、Alex Moldovan、Jasper De Moor 和来自 CodeSandbox 的 Danilo Woznica 为集成 sandbox 做出了贡献。感谢 Rick Hanlon 进行开发和设计工作,完善我们的颜色和细节。感谢 Harish Kumar 和 Luna Ruan 为网站添加新功能并帮助维护它。

非常感谢那些自愿参加 alpha 和 beta 测试计划的人。你们的热情和宝贵的反馈帮助我们塑造了这些文档。特别感谢我们的 beta 测试人员 Debbie O’Brien,她在 React Conf 2021 上分享了她使用 React 文档的经验。

最后,感谢 React 社区的启发,是你们促使我们完成了这个新的项目。我们希望新文档将帮助大家使用 React 构建任何你想要的用户界面。