likes
comments
collection
share

React 生态系统(2024 版本)

作者站长头像
站长
· 阅读数 4

原文链接:React Libraries for 2024,翻译时有删改。

导读:这是国外程序员 Robin Wieruch 带有明显个人色彩的一份总结,每年都会更新。相比于 awesome 列表,我个人更喜欢这类总结,简短、实用,更容易让人抓到重点并能立即实施。

React 的是一个由组件驱动的 UI 框架,JSX 以及 React Hook 都是其首创的先进理念。经过多年的发展,React 拥有一套非常庞大的生态系统,不过这也导致从其他库/框架转过来的开发人员带来选择困难。

React 通过 React Hooks 为编写组件提供了一些内置解决方案,包含管理本地状态、副作用和一些性能优化的 Hooks,不过能解决的问题有限。

接下来,我们将针对不同应用场景,深入了解一些 React 生态系统中我们可以使用的一些库。并且,每一小节最后都会包含我的一些个人推荐。

创建新项目

对 React 初学者来说,最受欢迎的方式时使用 Vite 来创建 React 项目。Vite 本身是一款通用开发打包工具,还支持其他框架项目的创建。

# Create a react project using `create-vite` CLI
npm create vite@latest my-vue-app -- --template react
# Create a react project with TypeScript support
npm create vite@latest my-vue-app -- --template react-ts

如果你已经熟悉 React,那么可以选择使用目前最流行的 Meta 框架之一的 Next.js。Next.js 基于 React 进行构建。另外一个流行的替代方案是 Remix

Next.js 最初用于服务端渲染,不过后面加入了静态内容渲染支持。2023 年,Next.js 在 App Router 中率先引入了 React Server 组件支持,编程模型从客户端移动到服务器端,是一次重大的编程范式转变。

如果你要寻找一个对静态内容渲染具有最佳性能的框架,那么可以看看 Astro。Astro 与框架无关,构建之后只会向浏览器提供 HTML 和 CSS,仅在页面组件在进行交互的时候,客户端才会请求必要的 JavaScript。

如果你想学习 Vite 的工作原理,那么可以参照 Vite 官方的 React 项目模板,从 0 到 1 的搭建一遍。虽然这不是你日常工作中必须要做的事情,但是自从 Vite 成为 webpack 的继承者之后,了解底层工具会对你编写项目提供更多自信。

如果你是 React 老手的话,并且想尝试一些新库那么可以看 NitroWaku。Waku 也是非常著名的状态管理库 Zustand 作者的作品,提供 React Server 组件支持。

建议

  • 使用 Vite 创建客户端渲染程序
  • 使用 Next.js 创建服务端渲染程序
  • 使用 Astro 创建静态页面程序

包管理器

提到 React 的包管理器,也就是在说 JavaScript 生态系统的包管理器。目前最被广泛使用的包括管理器是 npm,因为它是随 Node.js 一起安装的。不过现在大家更喜欢使用 yarn 或者pnpm,因为他们能带来更好的使用体验和更大的性能提升。

如果你发现创建的多个应用程序之间,出现多个相互依赖或是共享一组通用自定义 UI 组件的现象,那这时候可以了解一下多包仓库(monorepo)的概念,就是一个仓库中包含多个项目。

现在的包管理器都能通过 workspaces 特性来支持 monorepo 的构建,在这一点上 yarn、pnpm 比 npm 要好。当然,如果能再配合 Turborepo 这类 monorepo pipeline 工具的使用,体验会更好。

建议

  • 选择一个包管理器并坚持使用
    • 使用最广泛的是 npm
    • 希望有更好性能,但目前还没那么流行的就选 pnpm
  • 如果是 monorepo,请查看 Turborepo 相关教程

状态管理

React 本身提供了两个用于管理本地状态的 Hook:useStateuseReducer。像全局状态管理的话,可以选择使用内置的 useContext Hook,这就避免了层层父子组件进行 props 传递来共享状态的问题。

如果你发现自己很频繁地在使用 React 的 Context Hook 来实现共享/全局状态,这个时候就该看看 Zustand 了。它能帮助你更好的管理应用程序的全局状态,方便你在任意层级的 React 组件中进行状态的读取和修改。

虽然 Zustand 已经成为社区事实标准,不过说到状态管理库,你可能怎么也无法绕过 Redux——它现在仍然是最流行的状态管理库。 Redux 用起来比 Zustand 要复杂很多,不过实际上有很多旧的 Rect 应用程序在使用 Redux。

如果你正在使用 Redux,那你应该看看 Redux Toolkit。如果你对状态机感兴趣,可以查看XStateZag。如果你不喜欢使用 Zustand 或者 Redux 作为全局状态管理工具,那么还有一些其他流行的全局状态管理方案,例如:JotaiRecoilNano Stores

建议

  • useState/useReducer 用于 co-located 或共享状态
  • useContext 用于小范围状态(little global state)
  • Zustand(或其他替代方案)用于全局状态管理(lots of global state)

数据获取

React 提供了一些内置的管理本地状态的一些 Hook,不过当涉及到远程数据的状态管理时,我建议还是使用专用的数据获取库,比如说 TanStack Query(前身是 React Query)。

TanStack Query 并没有把自己定位成只是一个状态管理库,它主要是提供了 API 来获取远程数据,但会对获取到的数据进行状态管理(比如:缓存、乐观更新(optimistic updates))。

TanStack Query 专为 REST API 设计,不过它现在也支持 GraphQL。但是,如果你要寻找专为 GraphQL 设计的库,那么可以看一下 Apollo Client(流行)、urql(轻量)或 Relay(Facebook 出品)。

如果你正在使用 Redux,并且想要在 Redux 中添加集成了状态管理功能的数据获取方案,那么可以查看一下 RTK Query,它将数据获取的能力巧妙地继承到 Redux 中,而无需借助 TanStack Query。

最后要说的是,如果你需要同时控制前后端(均使用 TypeScript 编写),那么可以看看 tRPC,它能提供端到端类型安全的 API。去年我就一直在使用它,极大的提高了我的生产力和DX,并且它还能跟 TanS tack Query 很好的结合使用。

建议

  • TanStack Query 用于 REST APIs 活 GraphQL APIs
  • Apollo Client 专用于 GraphQL APIs
  • tRPC 提供前后端紧密耦合的 CS 架构

路由

如果你正在使用 Next.js 这样的 React 框架,那么就已经内置了路由的功能。但是,如果你是在没有框架的情况下使用了 React,比如你的项目是使用 Vite 来创建的纯客户端渲染项目,那么最强大和最流行的路由库,非 React Router 莫属了。TanStack Router 则是另一个完全支持 TypeScript 的新替代方案。

使用 React Router 做客户端路由时,基于路由的代码分割做起来并不复杂。如果你碰巧需要做这部分的优化,那么可以使用 @loadable/component 来替代 React.lazy()

React 中还有一套条件渲染技术,与路由功能有些相似,能实现页面级别上的组件替换,但只能处理一些简单的场景,是你在初学 React 会接触到一个技术。

建议

  • 最常用的:React Router
  • 未来趋势:TanStack Router
    • 主要是因为一流的 TS 支持

CSS 样式

React 关于设置样式有很多选择,本节并不能完全覆盖,在这里可以跟大家讲一个大概。

对于 React 的初学者而言,可以从在 JSX 中直接使用 style prop 对象设置内联样式开始,这是最简单的方式,虽然实际项目中很少使用。

const Headline = ({ title }) =>
  <h1 style={{ color: 'blue' }}>
    {title}
  </h1>

这种方案还可以搭配外部的 CSS 文件一起使用。

import './Headline.css';

const Headline = ({ title }) =>
  <h1 className="headline" style={{ color: 'blue' }}>
    {title}
  </h1>

一旦你的应用规模开始增大,就可以考虑其他的一些样式方案。

首先,我建议你了解一下 CSS 模块(CSS Modules),这是众多 CSS-in-CSS 解决方案之一。 CSS 模块提供了一种将 CSS 的封装与特定组件关联的技术(“component co-located modules”)。这样独属于本组件的样式,就不会泄露到其他组件中。

import styles from './style.module.css';

const Headline = ({ title }) =>
  <h1 className={styles.headline}>
    {title}
  </h1>

其次,我将向你展示另外一种样式化组件的方式,不过已经不再推荐了。这种方案的一个代表库就是 styled-components(或者 emotion),它借助 JavaScript 以及 React 组件的方式来创建并组织样式。

import styled from 'styled-components';

const BlueHeadline = styled.h1`
  color: blue;
`;

const Headline = ({ title }) =>
  <BlueHeadline>
    {title}
  </BlueHeadline>

第 3 个我想推荐的方案是以 Tailwind CSS 为代表的工具类优先的 CSS 解决方案。Tailwind CSS 中预定义了很多 CSS 类,简化了设计系统,可以让开发人员更加高效的开发。

const Headline = ({ title }) =>
  <h1 className="text-blue-700">
    {title}
  </h1>

不过,也带来了一些学习成本以及行内类名冗余的代价。这也正应了的那句话,没有哪种技术是最好的,一项技术推出的背后都是基于现状的一个权衡结果。

使用 CSS-in-CSS 还是工具类优先的 CSS 方案由你决定。趋势是向工具类优先的 CSS 方案倾斜。CSS-in-CSS 由于服务器端环境的问题不再那么流行。

最后一个温馨提示:如果在你的 React 项目中需要有条件的来应用 className,那么可以考虑使用像 clsx 这样的工具库。

建议

  • 工具类优先(最流行)
    • 例如:Tailwind CSS
  • CSS-in-CSS
    • CSS 模块
  • CSS-in-JS(由于存在问题,个人不再推荐)
    • Styled Components 或是 Facebook 的 StyleX
  • CSS-in-TS
    • 支持 TypeScript 和服务器端渲染

UI 库

作为 React 初学者,我还是建议先学习如何构建可重用组件,这会是很好学习效果。不管是下拉列表、选择、单选按钮还是复选框,你都应该知道如何来创建这些 UI 组件。

不过,如果你没有足够的资源来自己设计组件,那么就需要现成的一些 UI 库。UI 库一般会为你预置很多现成的组件,有统一的设计风格、丰富的功能交互或是可访问性支持。

不过,趋势正在转向无头 UI 库(headless UI libraries)。它们没有样式,但具有现代组件库所需的所有功能和可访问性。这里的大多数无头 UI 库,基本上都跟实用类优先的 CSS 解决方案(如 Tailwind CSS)结合使用:

这里还有一些 UI 库,相比其他我们已经说过的,可能会有一些过时。

以上这些都是综合性的 UI 库,包含很多内置组件。但功能上往往无法与只专注于一个 UI 组件的库强大。例如:react-table-library,是一个专注于展示表格的库,还为你提供了不同主题(比如: Material UI),方便你更好的与其他 UI 库配合使用。

动画库

我们通常会使用 CSS 来实现 Web 应用中的一些动画,当发现不够用的时候,通常会考虑 React Transition Group。其他一些有名的 React 动画库还包括:

可视化图表库

如果你想从头去构建自己的图表,那么使用 D3 是没有办法的。它是一个低抽象的可视化库,虽然能提供一切能帮你创建令人炫酷图表的能力,但是学习曲线过于陡峭。因此很多开发人员会损失灵活性,直接选择一个 React 图表库使用。

目前的流行解决方案是:

  • Recharts(个人比较推荐)
    • 现成的图表
    • 出色的可组合性
    • 支持定制
  • visx
    • 介于高层抽象与 D3 之间的水平
    • 更陡峭的学习曲线
  • 预制的图表类型越多,定制就越困难

表单库

React 中最流行的表单库是 React Hook Form,它具有表单库所需要的一切功能:验证(最常跟 zod 集成),表单提交、表单状态管理。其他一些替代方案有 FormikReact Final Form

推荐

  • React Hook Form
    • 与 zod 集成做校验

类型检查

React 附带了一个名为 PropTypes 的内部 props 验证库。通过使用 PropTypes,你可以为 React 组件定义传入 props 类型。每当传入错误的 prop 类型给组件时,都会收到一条错误消息:

import PropTypes from 'prop-types';

const List = ({ list }) => (
  <div>
    {list.map((item) => (
      <div key={item.id}>{item.title}</div>
    ))}
  </div>
);

List.propTypes = {
  list: PropTypes.array.isRequired,
};

不过,PropTypes 已经从 React 中移除了。现在,我不建议大家使用 PropTypes,出于历史原因,我仍然将它们保留在这里。

行业标准是在 React 应用程序中使用 TypeScript。如今,几乎所有新的 React 项目都采用 TypeScript 编写。

type Item = {
  id: string;
  title: string;
};

type ListProps = {
  list: Item[];
};

const List = ({ list }: ListProps) => (
  <div>
    {list.map((item) => (
    <div key={item.id}>{item.title}</div>
  ))}
  </div>
);

使用 TypeScript 编写代码是当今的主流方式。如果你想在 TypeScript 之外进行表单类型验证,API 验证(例如在使用 tRPC 时),可以看看 Zod

建议

  • 如果需要类型化 JavaScript,请使用 TypeScript

代码结构

如果你想在 React 项目中采用统一且通用的代码风格(code style),可以使用 ESLint。像 ESLint 这样的 Linter 工具会强制你的代码遵循某种格式。你可以使用 ESLint 要求遵循流行的风格指南,比如 Airbnb Style Guide,或是将 ESLint 集成到你的 IDE/编辑器中(比如 VSCode 的 ESLint 插件),去标识错误。

如果你想在 Raect 项目中采用统一的代码格式(code format),可以使用 Prettier。它是一个有主见(Opinionated)的代码格式化工具,只提供少数几种对外可供选择的配置。你可以将 Prettier 集成到你的 IDE/编辑器中(比如 VSCode 的 Prettier 插件),以便每次保存文件时都能自动格式化你的代码。Prettier 虽然并没有取代 ESLint,但它与 ESLint 集成得很好

也许 2024 年的后起之秀将是 Biome(以前的 Rome(已停止维护)),因为就交互而言,ESLint 和 Prettier 并不是最受欢迎的工具,不过却是现在每个 Web 开发人员的日常工作中都必需掌握的。Biome 希望通过提供快速(基于 Rust)且一体化的工具链来成为 Prettier 和 ESLint 的替代品。

建议

  • ESLint + Prettier,同时
  • 给 Biome 一个机会

认证

你可能要问你的 React 项目引入注册、登录和注销等功能做身份验证,或是其他像密码重置和密码更改的功能。这些功能远远超出了 React 的范围,因为这是后端应用程序会为你管理的事情。

最好的学习方式是自己实现一个身份验证的后端应用程序(例如 GraphQL 后端)。然而,由于身份验证涉及很多安全风险,并非每个人都知道的要注意的细节,因此我建议使用现成的很多身份验证/backend-as-a-service 解决方案:

后端

现在有一个很明显地将 React 转移到服务器的趋势,目前最自然的选择是像 Next.js、Astro 或 Remix 这样的元框架。

如果由于各种原因无法使用全栈框架(同时仍然可以使用 JS/TS),可以看看 tRPCHono。值得一提的是老派但仍然流行的 Express 框架,其他同类替代方案还有 FasitfyNest

数据库

这部分其实与 React 无关。但由于全栈 React 应用程序如今越来越流行,React 现在开始更接近数据库层了。在开发 Next.js 应用程序时,你很可能要处理数据库 ORM。目前最受欢迎的 ORM 是 Prisma。另一个流行的替代方案是 Drizzle ORM。其他一些的替代方案还包括 Kyselydatabase-js(仅限 PlanetScale)。

在选择数据库时,Supabase(或 Firebase)是比较可靠的数据库提供商。Supabase with its PostgreSQL 可以自行托管或使用付费服务。

其他提供 serverless 数据库的流行替代方案是 PlanetScale(个人推荐)、NeonXata

托管

你可以像任何其他 Web 应用程序一样部署和托管 React 应用程序。如果你想完全控制,可以选择 Digital Ocean 之类的服务商。如果你不想管太多,那么可以选择 NetlifyVercel(尤其是 Next.js)这些流行解决方案。

如果你已经在使用第三方后端作为服务(例如 Firebase/Supabase),你可以看看他们是否提供托管服务。其他流行的托管提供商包括 RenderFly.ioRailway,或直接在 AWS/Azure/Google Cloud/Hetzner 上托管。

测试

如果你想深入了解 React 中的测试,可以阅读这篇文章《How to test components in React》。要点:测试 React 应用程序的骨架通常需要像 Jest 这样的测试框架。

Jest 能为你提供测试运行器、断言库以及监测(Spying)、模拟等功能,也就是一个综合测试框架所需的一切。如果你是 Vite 的迷弟迷妹,那么可以选择 Vitest 作为 Jest 的替代。

最小化情况,你可以只使用 react-test-renderer 在测试框架中渲染 React 组件,Jest/Vitest 本身能提供快照测试。快照测试的工作方式如下:运行测试后,会创建一份 React 组件渲染的 DOM 元素的快照。当你在某个时间点再次运行测试时,会创建另一个快照,使用快照用与前一次快照的进行比对,如果不同,测试框架就会跟你抱怨,你要么必须接受快照,要么调整组件。

不过,现在最流行的 Raect 组件测试库还是 React Testing Library (RTL),RTL 可以用来渲染组件并且模拟 HTML 元素上的事件,而我们的测试框架则专门用于断言。

如果你正在寻找适用于 React 的端到端(E2E)测试工具,PlaywrightCypress 最受欢迎。

建议

  • 单元/集成测试:Vitest + React Testing Library (最受欢迎)
  • 快照测试:Vitest
  • E2E 测试:Playwright 或 Cypress

不可变的数据结构

原生 JavaScript 为你提供了大量内置工具方法来处理数据结构,不过好些工具方法都会对数据结构做修改。如果你和你的团队觉得需要强制执行不可变的数据结构,那么最受欢迎的选择是 Immer

国际化

当涉及 React 应用程序的国际化时,你不仅需要考虑翻译,还需要考虑多元化(pluralizations)、日期和货币的格式及其他一些事情。

以下是目前最流行的库:

富文本编辑器

说到 React 中的富文本编辑器,我只能想到以下几个:

付款

最常见的支付提供商是 Stripe 和 PayPal。两者都可以巧妙地集成到 React 中。这里有一个与 React 集成的有效 Stripe 模板方案

时间

如果你的 React 项目中要大量处理日期、时间和时区,那么可以引入一个库来为你管理这些事情。以下是我推荐的一些选择:

桌面程序

ElectronTauri 是跨平台桌面应用程序的首选框架。

文件上传

邮件

拖放

我使用过 react-beautiful-dnd 的后继者 @hello-pangea/dnd,所以我不能对它说任何负面的话(狗头)。

dnd kit 是一种流行的替代方案,提供了更多的灵活性和选项,但代价是学习曲线更陡峭。这个领域的另一个替代方案是 react-dnd

移动开发

将 React 从 Web 引入移动设备的首选解决方案仍然是 React Native,用来创建 React Native 应用程序的最流行框架是 Expo

如果你需要跨 Web 和移动设备的统一组件,可以看看 Tamagui

VR/AR

React 也可以应用于虚拟现实或增强现实。老实说,我没有使用过任何这些库,而且大多数都还处于早期阶段(实验性),但当涉及到 React 中的 AR/VR 时,我从头到尾就知道它们:

原型设计

如果你有 UI/UX 背景,可能希望使用一个工具来快速构建新的 React 组件、布局的原型。我个人在使用 Figma。对于粗糙但轻量级的原型,我喜欢使用 Excalidraw,其他还有一些人更喜欢 tldraw

组件文档

如果你负责负责组件编写文档,那么目前网络上有各种简洁的 React 文档工具。我在很多项目中使用过 Storybook,不过对它持中立看法。我也听说过有关其他好的解决方案:

总结

我们可以把“React 生态系统”看成是以 React 为核心的“框架”,这是有一定灵活性的。你可以基于项目的自身状况,自行决定要采用加入哪些库。当然,你也可以从小处开始,先添加一些库来解决特定问题。相比之下,如果你需要 React,那么只用 React 来保持项目轻量也完全没问题。