介绍 react.dev

2023 年 3 月 16 日,来自 Dan Abramov 和 Rachel Nabors


今天我们非常高兴地推出 react.dev,这是 React 及其文档的新家。在这篇文章中,我们将带你参观这个新网站。


简而言之

  • 新的 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 的细节和使用示例。

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

Note

仍然有少数罕见的类组件使用场景,还没有基于 Hook 的等价实现。类组件仍然受支持,并在新站点的 旧版 API 部分中有文档说明。

快速开始

“学习”部分从 快速开始 页面开始。这是一段简短的 React 入门导览。它介绍了组件、props 和 state 等概念的语法,但不会深入讲解如何使用它们。

如果你喜欢边做边学,我们建议下一步查看 井字棋教程。它会带你用 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;
  } else {
    status = '下一位玩家:' + (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 = '转到第 ' + move + ' 步';
    } else {
      description = '回到游戏开始';
    }
    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,**所以它们焕然一新。

Note

上面的示例是一个 sandbox。我们在整个网站中加入了很多 sandbox——超过 600 个!——你可以在任何地方看到它们。你可以编辑任意 sandbox,或点击右上角的“Fork”在新标签页中打开它。sandbox 能让你快速尝试 React API、探索你的想法,并检查自己是否真正理解。

逐步学习 React

我们希望世界上每个人都有平等机会,可以免费、独立地学习 React。

这也是“学习”部分被组织成一个自定进度、按章节划分的课程的原因。前两个章节介绍 React 的基础知识。如果你是 React 新手,或者想回顾一下,就从这里开始:

接下来的两个章节更高级,会让你更深入了解那些更棘手的部分:

  • 管理状态 教你如何在应用复杂度增长时组织逻辑。
  • 逃生舱口 教你如何“走出” React,以及在什么情况下这样做最合适。

每个章节都由若干相关页面组成。这些页面大多教授某项具体技能或技术——例如,使用 JSX 编写标记、更新 state 中的对象 或 在组件之间共享 state。有些页面专注于解释一个概念——比如 渲染与提交 或 快照中的 state。还有一些页面,比如 你可能不需要 Effect,会基于我们这些年来学到的经验分享我们的建议。

你不必按顺序阅读这些章节。谁有这个时间啊?!不过你也可以这么做。“学习”部分中的页面只依赖于前面页面介绍过的概念。如果你想把它当作一本书来读,那就尽管去读吧!

通过挑战检验你的理解

“学习”部分中的大多数页面都会在结尾提供一些挑战题,用来检验你的理解。例如,这里有几个来自 条件渲染 页面上的挑战题。

你现在不必马上解答它们!除非你真的想。

Challenge 1 of 2:
为未完成项目显示一个 ? : 图标

使用条件运算符(cond ? a : b)在 isPacked 不为 true 时渲染一个 ❌。

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

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride 的打包清单</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 的图:

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'.

Illustrated by Rachel Lee Nabors

我们已经向浏览器厂商确认,这幅图在科学上 100% 准确。

一个全新的、详细的 API 参考

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

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

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

用法 会像同事或朋友一样,展示你为什么以及如何在实践中使用这个 API。它展示了** React 团队认为每个 API 应当被使用的典型场景。** 我们添加了带颜色标记的代码片段、多个 API 组合使用的示例,以及你可以复制粘贴的配方:

useState 基础示例

Example 1 of 4:
计数器(数字)

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

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 中的 bug,甚至是 React 设计中的一些空白,而我们现在正努力解决这些问题。我们希望新的文档将帮助我们在未来对 React 本身提出更高的要求。

我们听到了许多你们希望扩展网站内容和功能的请求,例如:

  • 为所有示例提供 TypeScript 版本;
  • 创建更新后的性能、测试和可访问性指南;
  • 将 React Server Components 与支持它们的框架分开进行文档编写;
  • 与我们的国际社区合作,将新文档翻译出来;
  • 为新网站添加缺失的功能(例如,这篇博客的 RSS)。

现在 react.dev 已经上线,我们将能够把重点从追赶第三方 React 教学资源,转移到添加新信息并进一步改进我们新的网站上。

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

谁参与了这个项目?

在 React 团队中,Rachel Nabors ხელმძღვანed 这个项目(并提供了插图),而 Dan Abramov 设计了课程。他们也共同撰写了大部分内容。

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

Sylwia Vargas 彻底改造了我们的示例,让它们不再局限于“foo/bar/baz”和小猫,而是加入了来自世界各地的科学家、艺术家和城市。Maggie Appleton 将我们的涂鸦变成了一套清晰的图表系统。

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

感谢 Dan Lebowitz 提供网站设计,以及 Razvan Gradinar 提供 sandbox 设计。

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

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

最后,感谢 React 社区成为这项工作的灵感来源。正是因为你们,我们才在做这件事,我们也希望新的文档能帮助你们使用 React 构建任何你想要的用户界面。