2023 React 生态系统,以及我的一些吐槽……
首发于公众号 前端从进阶到入院,欢迎关注。
HI 大家好,我是 ssh。
最近外网有人总结了一篇文章 2023 的 React 生态系统,列出了 React 整个生态系统中比较火热的库。可惜的是他仅仅列出了名字,没有继续深入介绍,我知道读者们有很多小懒蛋,那我就花点时间收集一些重点框架的详细介绍,如果我有一些看法(吐槽),我也会在下面的引用部分进行一些评价。
2023 年的 React 生态系统
随着技术的不断发展,工具和库也在不断演进。最近发布了 million.js,使 React 的性能提升了 70%。对于初学者来说,选择正确的库可能会很具有挑战性。
在这里,我将列出一些 React 库,供你学习并成为 React 开发者。
构建工具
vite
Vite(法语意为 "快速的",发音 /vit/,发音同 "veet")是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:
-
一个开发服务器,它基于 原生 ES 模块 提供了 丰富的内建功能,如速度快到惊人的 模块热更新(HMR)。
-
一套构建指令,它使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。
Vite 意在提供开箱即用的配置,同时它的 插件 API 和 JavaScript API 带来了高度的可扩展性,并有完整的类型支持。
nextjs
Next.js 是一个用于构建 Web 应用程序的框架。
使用 Next.js,你可以使用 React 组件构建用户界面。然后,Next.js 为你的应用程序提供额外的结构、功能和优化。
在背后,Next.js 还为您抽象和自动配置工具,例如打包、编译等。这使你可以专注于构建应用程序,而不是花时间设置工具。
无论你是独立开发者还是大团队的一部分,Next.js 都可以帮助你构建交互式、动态和快速的 Web 应用程序。
路由
react-router
React Router 不仅仅是将 URL 与函数或组件匹配:它还涉及构建一个完整的用户界面,该界面与 URL 相对应,因此可能比你习惯的更多概念。我们将详细介绍 React Router 的三个主要功能:
- 订阅和操作历史记录堆栈
- 将 URL 与你的路由匹配
- 根据路由匹配呈现嵌套的 UI
想深入了解的话,请看这里:React Router 基本概念
Tanstack Router
TanStack Router 是一个用于使用你喜爱的现代 Web 框架构建 Web 应用程序的路由器。它的一些特点包括:
- 100%推断的 TypeScript 支持
- 类型安全的绝对和相对导航
- 嵌套路由和布局路由
- 集成的路由加载 API(数据、资源、暂停)
- 为 state-while-revalidate 缓存设计(TanStack 加载器、TanStack 查询、SWR 等)
- 自动路由 prefetching
- Suspense-like 的路由过渡
- 异步路由元素和错误边界
- 类型安全的 JSON-first 搜索参数状态管理 API
- 路径和搜索参数 Schema 校验
- Serach 参数导航 API
- 自定义 Serach 参数解析器/序列化器支持
- Serach 参数中间件
- 路由匹配中间件
官方给出了一张对比图,仅供参考。
大致可以看出,TanStack Router 的主要优势在于类型安全、SWR 策略以及 Devtools 支持等等……
如果你使用的是 Next.js,则不需要使用路由,因为它内置了路由功能。
客户端状态管理
大家都知道,redux sucks!官方为了补救,推出了一系列的 toolkit,把 redux 搞的更复杂了,怎么说呢,大型复杂项目里也许可以试试。
Redux Toolkit 软件包旨在成为编写 Redux 逻辑的标准方式。它最初的创建目的是解决 Redux 中的三个常见问题:
- "配置 Redux store 太复杂"
- "我必须添加很多包才能让 Redux 有用"
- "Redux 需要太多样板代码" 尽管我们不能解决所有用例,但我们试图在 create-react-app 的精神下提供一些工具,它们可以抽象化设置过程、处理最常见的用例,并包含一些有用的实用工具,让用户可以简化他们的应用程序代码。
Redux Toolkit 还包括一个强大的数据获取和缓存功能,我们将其称为 "RTK Query"。它作为一个独立的入口点包含在软件包中。它是可选的,但可以消除手动编写数据获取逻辑的需求。
这些工具对所有的 Redux 用户都应该有益。无论你是个新 Redux 用户,还是一个经验丰富的用户希望简化现有的应用程序,Redux Toolkit 都可以帮助改进你的 Redux 代码。
多了一堆复杂的概念,又有一堆人要加工资了,又有一堆小弟要被迫学习了。笔者本人是完全不感冒的,辣鸡不如 jotai。
zustand
一个小巧、快速和可扩展的基于简化 Flux 原则的骨架状态管理解决方案。它具有基于 hooks 的舒适 API,没有样板代码,也没有过多的观点。
不要因为它看起来可爱而忽视它。它拥有强大的能力,花费了大量时间来解决常见的陷阱,比如可怕的僵尸子问题、React 并发和混合渲染器之间的上下文丢失。在 React 领域,它可能是唯一一个完全解决这些问题的状态管理器。
看起来不错,简洁明了而且是 mutable 风格,不用做一堆复制 object 的骚操作了。
服务器状态管理
tanstack query
TanStack Query(前身为 React Query)经常被描述为 Web 应用程序中缺失的数据获取库,但更具技术性的说法是,它使得在 Web 应用程序中获取、缓存、同步和更新服务器状态变得轻而易举。
大多数核心的 Web 框架没有提供一种明确的方式来全面获取或更新数据。因此,开发人员要么构建封装了对数据获取的严格观点的元框架,要么发明自己的数据获取方式。这通常意味着将基于组件的状态和副作用凑合在一起,或者使用更通用的状态管理库在应用程序中存储和提供异步数据。
虽然大多数传统的状态管理库非常适合处理客户端状态,但在处理异步或服务器状态时效果不佳。这是因为服务器状态与众不同。首先,服务器状态具有以下特点:
- 以你无法控制或拥有的远程位置持久存储
- 需要使用异步 API 进行获取和更新
- 暗示共享所有权,并且可能被其他人在你不知情的情况下更改
- 如果不小心处理,可能会在应用程序中变得“过时”
一旦你理解了应用程序中的服务器状态的性质,你将面临更多挑战,例如:
- 缓存...(可能是编程中最难的事情之一)
- 将多个请求相同数据的重复请求合并为单个请求
- 在后台更新“过时”的数据
- 了解数据何时“过时”
- 尽快反映数据的更新
- 性能优化,如分页和惰性加载数据
- 管理服务器状态的内存和垃圾回收
- 使用结构共享对查询结果进行记忆化
如果你对这个列表不感到压力,那可能意味着你已经解决了所有服务器状态问题,并且值得获得奖励。然而,如果你和大多数人一样,你可能尚未解决所有或大部分这些挑战,我们只是触及到了表面!
React Query 毫无疑问是管理服务器状态的最佳库之一。它可以直接使用,零配置,并且可以根据你的需求进行定制,随着应用程序的发展。
React Query 让你能够战胜服务器状态的复杂挑战和障碍,在它开始控制你的应用程序数据之前掌控它。
从技术角度来看,React Query 很可能:
- 帮助你从应用程序中删除许多复杂和误解的代码,并用几行 React Query 逻辑替代。
- 使你的应用程序更易于维护,更容易构建新功能,而无需担心连接新的服务器状态数据源。
- 对你的最终用户产生直接影响,使你的应用程序感觉比以往更快、更响应。
- 潜在地帮助你节省带宽并提高内存性能。
redux-toolkit query
RTK Query 是一个强大的数据获取和缓存工具。它旨在简化 Web 应用程序中加载数据的常见情况,消除了手动编写数据获取和缓存逻辑的需求。
RTK Query 是 Redux Toolkit 包中包含的一个可选附加组件,它的功能是构建在 Redux Toolkit 的其他 API 之上的。
通常,Web 应用程序需要从服务器获取数据才能显示。它们通常还需要对该数据进行更新、将更新发送到服务器,并使客户端上的缓存数据与服务器上的数据保持同步。这在实现当今应用程序中使用的其他行为时变得更加复杂:
- 跟踪加载状态以显示 UI 加载指示器
- 避免对相同数据进行重复请求
- 进行乐观更新以提高 UI 响应速度
- 随着用户与 UI 进行交互,管理缓存的生命周期
- Redux 核心一直非常简洁 - 开发人员需要编写所有实际逻辑。这意味着 Redux 从未包含任何内置功能来帮助解决这些用例。Redux 文档教授了一些常见的模式,用于在请求生命周期中分派操作以跟踪加载状态和请求结果,并且 Redux Toolkit 的 createAsyncThunk API 是设计为抽象化该典型模式的。然而,用户仍然需要编写大量的 reducer 逻辑来管理加载状态和缓存数据。
在过去的几年中,React 社区意识到“数据获取和缓存”实际上是与“状态管理”不同的一组问题。虽然可以使用像 Redux 这样的状态管理库来缓存数据,但这些用例足够不同,值得使用专为数据获取用例而构建的工具。
RTK Query 从先驱解决数据获取问题的其他工具(如 Apollo Client、React Query、Urql 和 SWR)中获得灵感,但在其 API 设计中增加了独特的方法:
- 数据获取和缓存逻辑是构建在 Redux Toolkit 的 createSlice 和 createAsyncThunk API 之上的
- 由于 Redux Toolkit 是与 UI 无关的,RTK Query 的功能可以与任何 UI 层一起使用
- API 端点是预先定义的,包括如何从参数生成查询参数和将响应转换为缓存的方式
- RTK Query 还可以生成封装整个数据获取过程的 React hooks,为组件提供数据和 isLoading 字段,并在组件挂载和卸载时管理缓存数据的生命周期
- RTK Query 提供了“缓存条目生命周期”选项,可以通过 WebSocket 消息流式传输缓存更新,以在获取初始数据后使用
- 我们有从 OpenAPI 和 GraphQL 模式生成 API 切片的早期工作示例
- 最后,RTK Query 完全使用 TypeScript 编写,并旨在提供出色的 TypeScript 使用体验。
这复杂的 API 风格,欣赏不来。
Apollo Client
Apollo Client 是一个全面的 JavaScript 状态管理库,可让您使用 GraphQL 来管理本地和远程数据。使用它来获取、缓存和修改应用程序数据,同时自动更新用户界面。
Apollo Client 帮助您以经济、可预测和声明式的方式组织代码,与现代开发实践一致。核心的 @apollo/client 库提供了与 React 的内置集成,而更大的 Apollo 社区则维护了与其他流行的视图层的集成。
应该是用 GraphQL 时的状态管理最佳选择。
表单处理
面对现实吧,在 React 中处理表单确实很冗长。更糟糕的是,大多数表单辅助工具做了太多的魔法,并且通常会伴随着显著的性能损耗。Formik 是一个小型库,可以帮助您解决以下三个最令人讨厌的问题:
- 将值放入和取出表单状态
- 验证和错误消息
- 处理表单提交
- 通过将所有这些放在一个地方,Formik 可以让事情井然有序,使得测试、重构和理解您的表单变得轻而易举。
我(@jaredpalmer)在与 @eonwhite 一起构建一个大型内部管理仪表板时编写了 Formik。由于大约有 30 个独特的表单,很快就明显发现,我们可以通过标准化不仅是输入组件,还有数据在表单中的流动方式来获益。
为什么不使用 Redux-Form? 到现在为止,您可能会想,“为什么你不只是使用 Redux-Form?”问得好。
- 根据我们的先知 Dan Abramov 的说法,表单状态本质上是短暂且局部的,因此在 Redux(或任何 Flux 库)中跟踪它是不必要的。
- Redux-Form 在每次按键时都会多次调用整个顶层 Redux reducer。对于小型应用程序来说这没问题,但如果您使用 Redux-Form,随着 Redux 应用程序的增长,输入延迟将继续增加。
- Redux-Form 的大小是 22.5 kB(经过最小化和 gzip 压缩),而 Formik 的大小是 12.7 kB。 我创建 Formik 的目标是打造一个可扩展且高性能的表单辅助工具,具有最小化的 API,它可以处理那些真正令人讨厌的事情,而将其余部分留给您来处理。
import React from "react";
import { Formik } from "formik";
const Basic = () => (
<div>
<h1>Anywhere in your app!</h1>
<Formik
initialValues={{ email: "", password: "" }}
validate={(values) => {
const errors = {};
if (!values.email) {
errors.email = "Required";
} else if (
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = "Invalid email address";
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
/* and other goodies */
}) => (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{errors.email && touched.email && errors.email}
<input
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
)}
</Formik>
</div>
);
export default Basic;
作者自述:我对 React 最大的抱怨就是表单。不是因为我认为 React 在实现表单方面采取了错误的方法,而是因为在使用 React 时,表单是最具挑战性的问题。
许多框架都有自己的解决方案来处理表单。AngularJS 在这方面做得非常好。格式化流水线、解析流水线、内置验证,根据状态向元素添加和移除类名...这一切都很棒!
直到你需要做一些不符合 AngularJS 设计思路的事情。如果你需要做任何特殊的操作,与表单进行交互就变得非常痛苦!
因此,React 做了它最擅长的事情,将实现的工作交给了我们。事实上,这正是我喜欢 React 的原因!然而,相比起将数据传递给 props,处理表单要更具挑战性。解析数据、格式化、本地状态、prop 的变化...所有这些在 React 中都是挑战。
我之前使用过 Formik,但成果并不太理想。对于普通的表单来说,它表现得很好,但在多步骤表单方面有些困难。虽然后来他们添加了“向导”表单,但使用起来并不太直观。
此外,Formik 依赖于表单元素,并且在控制 Redux 存储时存在一些挑战。
import { useForm } from "react-hook-form";
export default function App() {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm();
const onSubmit = (data) => console.log(data);
console.log(watch("example")); // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<input defaultValue="test" {...register("example")} />
{/* include validation with required or other standard HTML validation rules */}
<input {...register("exampleRequired", { required: true })} />
{/* errors will return when field validation fails */}
{errors.exampleRequired && <span>This field is required</span>}
<input type="submit" />
</form>
);
}
测试
样式
Taiwlind 就不需要多介绍了,最近太火热了,而且可以和 Styled Components 库结合使用。
关于两个 CSS-in-JS 库,引用这篇文章里作者的总结:对于简单、高效和不复杂的样式处理,Emotion 是一个很好的 CSS-to-JS 库。另一方面,对于更独特和复杂的样式选项,styled-components 可能是更好的选择。就像写 CSS 一样,很大程度上取决于项目设置和个人偏好。
UI 组件库
- Material UI
- Mantine UI
- Ant Design
- Chakra UI
- Headless UI(Tailwind CSS)
- DaisyUI(Tailwind CSS)
- shadcn UI(Tailwind CSS)
UI 组件,就看风格和公司需求选择,各有各的好处。Headless 是值得一提的,引用这篇全新的 React 组件设计理念 Headless UI 里的介绍:UI 是一个自由度非常高的玩意,而构建 UI 是一种非常品牌化和定制化的体验。
那么,我们能不能只需复用组件的交互逻辑,布局和样式完全自定义呢?显然,Headless UI 就是干这件事情的。
对于 Headless UI 组件,我们要做到第一件事,就是分析和抽离组件的状态以及交互逻辑。对于 Counter 组件,它的状态逻辑大致如下:
我们把这些状态逻辑收敛到一个叫 useCounter 的 React Hook 中。它接收用户传入的功能 API 设置,然后返回一套已处理过的全新 API。
对于用户而言,我们只需把返回的 API 赋予到想赋予的标签上,那么就得到了一个只带交互能力的无头组件。
最后,我们结合设计稿进行 UI 还原,对编写自定义样式,最终就能实现一个全新数字加减器组件了;
动画
React Spring 是一个用于构建交互式,数据驱动和动画 UI 组件的库。它可以为 HTML,SVG,Element,ThreeJS 等元素做动画。
Framer Motion 是一个简单而强大的 React 动画库。
它为 Framer(面向创意专业人士的 Web 构建工具)提供了令人惊叹的动画和交互功能。零代码,最大速度。
数据可视化
图表库国内还是以 Echarts 为主,不过老外好像不吃这一套?md,和美团拼了。
Recharts 的审美风格看起来挺简洁的,不过应该又要学一套概念。
表格
TanStack Table 是一个 headless UI 库,用于为 TS/JS、React、Vue、Solid 和 Svelte 构建强大的表格和数据网格。
咱们刚刚看到的 headless UI 的概念,这就有例子了。那优点肯定就是多框架适配,样式自由定制了。
国际化(i18n)
react-i18next
react-i18next 是基于 i18next 的一款强大的国际化框架,可以用于 react 和 react-native 应用,是目前非常主流的国际化解决方案。
根据这篇文章的介绍,i18next 有着以下优点:
- 基于 i18next 不仅限于 react,学一次就可以用在其它地方
- 提供多种组件在 hoc、hook 和 class 的情况下进行国际化操作
- 适合服务端的渲染
- 历史悠久,始于 2011 年比大多数的前端框架都要年长
- 因为历史悠久所以更成熟,目前还没有 i18next 解决不了的国际化问题
- 有许多插件的支持,比如可以用插件检测当前系统的语言环境,从服务器或者文件系统加载翻译资源
formatjs
开发工具
- React Developer Tools
- Redux DevTools
- Testing Playground
- React Hook Form Dev Tools
- Tanstack Query Dev Tools
首发于公众号 前端从进阶到入院,欢迎关注。
转载自:https://juejin.cn/post/7248281795937959996