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

React 是什么?

一个带有按钮的页面需要在每次点击时保持点击计数器同步。用普通 JavaScript 写的话,你需要抓住那个按钮的文本节点,添加点击监听器,然后每次有人点击时手动更新这个数字。再加上搜索过滤、购物车总额和一个可以打开关闭的模态框,代码里就散落了一大堆手动更新,每一处都是当页面其他地方数据改变时 bug 可能溜进来的地方。

React 是一个用来用组件构建用户界面的 JavaScript 库,它把这种手动记账的工作从你肩上卸下来。这一章看看这实际上意味着什么:React 背后的核心理念、它在哪里运行,以及它如何适应库和框架的区分问题(大多数人学习 React 时早期都会碰到这个问题)。

组件和核心理念

同一个点击计数器,用 React 组件来写是这样的:

jsx
import { useState } from 'react'

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

  return (
    <button onClick={() => setCount(count + 1)}>
      点击了 {count} 次
    </button>
  )
}

这个例子用了几个你还没见过的东西:return 里面的标记是 JSX,useState 是一个 hook,onClick 是事件处理器。组件JSX 这两章会讲那个标记,State 会完整讲解 useState事件 会讲 onClick,所以现在就先相信这个语法,跟着这个思路理解就行。

count 是状态。Counter 返回的 JSX 描述了这个状态下按钮应该显示什么样。点击按钮会调用 setCount,这更新了 count,React 就重新渲染按钮来匹配新的值。你永远不会直接碰按钮的文本。你只是为新值重新描述它,React 就会算出页面上哪些东西变了。

这就是每个 React 组件背后的核心理念:你把 UI 描述成数据(通常叫状态)的函数,React 负责更新 DOM 来匹配。一个**组件**是一个返回一段 UI 的函数,一个应用就是组件树组合在一起,都以上面计数器那样的方式工作。

值得精确对比的是声明式和命令式。命令式代码,也就是直接操作 DOM,列出各个步骤:找到这个元素,改它的文本,加这个 class。声明式代码,也就是一个组件返回的东西,列出最终状态:给定这些数据,按钮应该显示什么。React 来执行中间的那些步骤。

这些步骤通过虚拟 DOM 运行:一个轻量级的内存表示,React 从你的组件返回的东西构建它,和前一个版本比较,用来算出最少需要做多少真实 DOM 改动。这个机制存在,现在可以先放到一边。你不创建它、不读它、不直接管理它;它是 React 内部的机制,用来实现"让 DOM 匹配"这个模型的后半部分。

剩下一个心智模型值得为了阅读本手册的其他内容而记住:UI = f(state)。一个组件是它的数据的函数,hooks、重新渲染和副作用都是建立在这个单一理念的基础上。你后面看到的大多数看起来像是独立的 React 概念,实际上都是这个理念的结果。

React 在哪里运行

React 主要在浏览器里运行,把组件渲染到 DOM。本手册全程都停留在这个环境里。

不过 React 的组件模型并不绑定到 DOM 特别是什么。其他的渲染器可以把同样的模型插入不同的目标。最著名的例子是 React Native,它用 React 的组件和状态模型来驱动原生移动界面,而不是网页。这里提一下是为了这个名字后面出现时你不会吃惊。教它不在本手册的范围里。

库还是框架?

React 渲染 UI。它不提供路由,不决定你怎么加载数据,也不处理服务器渲染。这些都是你自己做的选择,通常是通过找另一个工具配合它来实现。这就是 React 属于库而不是完整框架的实际原因:它把一件事做得很好,其他的留给你,而不是像框架那样拥有整个应用。

框架的种类 会完整讲这个区分,包括 React 如何和 Next.js 这样的东西一起发挥作用(它会补上那些缺失的部分)。

JunoUI 作为状态的函数 React 的全部归结为一个习惯:描述你拥有的数据下屏幕应该看起来什么样,让 React 来处理改动。你不伸手进去手动编辑页面,你说它应该显示什么,React 就跟上来。它在浏览器里还是在像 React Native 这样的地方运行,都是后续才要关心的细节。现在最重要的是这个习惯。
JunoUI 作为状态的函数 养成把组件写成状态的函数的习惯:给定这些数据,就渲染这样。每一次你都在做这个,不管是按钮上的点击计数还是整个页面。React 处理 DOM 更新,所以你不用手写,把它叫做库而不是框架是准确的:它渲染 UI,路由、数据加载和渲染策略都留给你。
JunoUI 作为状态的函数 把 UI = f(state) 作为随后一切的框架来记住。组件是数据的函数,虚拟 DOM 是 React 自己的记账方式,用来把一次渲染变成下一组 DOM 改动,声明式比命令式更优越这里,是因为你不用自己追踪更新步骤。这就是为什么它属于库而不是框架:它停在渲染,路由、数据加载和服务器渲染都留给你配合使用的任何东西。

下一步:历史和版本,讲 React 是怎么走到今天的,还有每个发行版中的变化。