Skip to content
This page has been auto-translated and may contain errors.View in English

历史和版本

React 已经存在了足够长的时间,经历了几个明显不同的阶段。了解这段历史的大致轮廓能帮助你读懂在现实中遇到的代码。2017 年的教程和今天的教程都讲 React,但看起来完全不同。这章会梳理时间线,解释你会碰到的两种写法。

简要时间线

React 起源于 Facebook,当时他们需要让大型、数据密集的界面保持同步,而不是手动更新 DOM。它在 2013 年作为开源项目发布,核心理念一直没变:根据你的当前数据描述 UI,让 React 处理更新。围绕这个核心,React 的几乎所有其他方面都在演变。

在最初的几年里,一个需要记住某些状态的组件是用 JavaScript class 写的。Class 是普通的 JavaScript 特性,React 用它给组件提供了一个地方来存储随时间变化的数据,以及一套特殊命名的方法,React 会在特定时刻调用:组件首次出现在屏幕上时、组件更新时和组件被移除时。这种风格曾经是默认写法,所以现在很多现存的 React 代码都是这样写的。

真正的转变来自于 hooks,它在 2019 年初的 React 16.8 中问世。Hook 是 React 提供给你的函数,让普通的函数组件能做以前只有 class 才能做的事情,比如在渲染之间记住一个值。编写组件变得简洁得多,函数组件很快就成了新代码的默认写法。Hooks 这章会详细讲解。现在要记住的是,hooks 让现代的写法成为可能。

React 继续发展:React 18 在 2022 年发布,React 19 在 2024 年发布,每个版本都增加了新功能,改进了粗糙的地方。这些发布主要在你构建真实应用时才重要,它们会在相关章节中讨论。

大体上就是这个进程。你不需要记住日期。关键是 React 有很长的历史,核心理念一直保持稳定,写法已经明确朝向函数组件和 hooks 发展。

野外的两种 React 写法

正因为这段历史,你会遇到两种明显不同风格的 React 代码。

较早的风格用 class 写组件。组件的状态数据存在 class 内部,React 在组件生命周期的特定时刻调用特殊命名的方法。大量的生产代码仍然这样运行,很多较早的教程、博客文章和 Stack Overflow 回答都是这种风格。它仍然有效,也仍然被支持。它只是 React 更早的写法。

较早写法是什么样的

这个手册不教这种风格,你也不需要写它。能识别它是很有用的,因为你会遇到。一个较早的代码库中的组件看起来大概是这样的:

jsx
class Counter extends React.Component {
  state = { count: 0 }

  componentDidMount() {
    // React 只在组件首次出现在屏幕上时调用这个方法一次
  }

  render() {
    return <button>Clicked {this.state.count} times</button>
  }
}

三个特点标识了它:顶部的 classextends React.Component,存储状态数据的 this.state,以及以 component 开头的方法名,React 会在设定的时刻自动调用。

现代风格用 函数 写组件,用 hooks 给它记忆和响应变化的能力。这是新 React 代码的写法,也是官方文档现在首先教的。

这门课程教的是现代 React:始终用函数组件和 hooks。在你可能遇到较早的 class 风格等价物的地方(可能是工作中的代码库或较早的教程),我们会标注它,这样两种写法在你脑子里就能联系起来,谁也不会让你懵。

自 hooks 以来的两个发布值得用名字来记住。2022 年的 React 18 引入了并发渲染:React 获得了在后台准备更新并中断工作以保持界面响应性的能力。它还改变了应用的启动方式,把入口点改到了 createRoot,这让应用可以利用这些新功能。

2024 年的 React 19 继续这个方向。它为处理表单提交和待处理状态添加了 Actions,添加了在渲染期间读取 promise 和 context 这类资源的 use hook,还让你可以像传普通 prop 一样传 ref,不用再用 forwardRef。与发布同步,React 编译器自动处理记忆化:开发者以前用 useMemouseCallback 手动做的工作现在可以在构建时处理。

Hooks 取代了 class 而不是与它并存,因为 class 模型让有状态逻辑很难共享。在组件之间复用行为意味着用高阶组件包裹它们,或者通过 render props 传递,这两种方式都会嵌套你的树并隐藏逻辑实际在哪里。Hooks 让你把逻辑提取到一个普通函数(自定义 hook)中,从任何组件调用它。复用变得简单得多。Hooks 还规避了 this:class 组件强制你绑定方法并推理 this 在调用时指什么,这是函数组件没有的常见 bug 来源。

React 18 的并发工作是比 createRoot 替换更深层的变化。它改变了渲染本身的行为,远低于你调用的 API 级别。React 现在可以开始一个渲染,暂停它,然后恢复或放弃它,这意味着渲染不再保证一次性从头到尾完成。startTransition 和 Suspense 驱动的数据加载这样的特性都建立在它之上。这就是为什么 createRoot 很重要,不仅仅是一个新函数名:选择加入才让 React 能以这种方式调度和中断渲染。

从这里开始,手册会用现代风格构建,Components 是真正开始的地方:一个组件就是返回你 UI 一部分的函数。但在任何代码运行之前,你需要安装 React 并在你自己的机器上让它运行。

Juno两种风格,同一个 React 如果你找到一个教程里的组件用 classthis.state 以及 componentDidMount 写的,别慌,别觉得你做错了。那是较早的 React 风格,它仍然有效。这门课程用的是较新的风格,函数组件配 hooks,当我们经过较早的等价物时我会标注,这样就不会有什么让你吃惊。
Juno两种风格,同一个 React 读实际代码的快速导览:有 this.state 和生命周期方法的 class 是 hooks 前的风格,有 useStateuseEffect 的函数是现代 React。工作中你会看到两种。我们这里用现代风格构建,当你实际会遇到 class 风格时我会标注出它的等价物。
Juno两种风格,同一个 React 要理清的发布:16.8 的 hooks 改变了默认的写法风格,修复了不用 HOC 或 render props 的逻辑复用;18 引入了并发渲染并把入口点改到 createRoot;19 添加了 Actions、use hook 和 ref 作为 prop。Hooks 和并发这两个变化深入到了渲染语义,值得在机制层面理解。

接下来:搭建 React 项目,在那里你会让 React 在你自己的机器上运行。