探索vurb.ts:基于Proxy的现代React状态管理库
1. 项目概述:一个面向未来的前端状态管理库
最近在折腾一个内部的管理后台项目,状态管理这块儿又成了团队讨论的焦点。Redux 的样板代码写起来还是有点繁琐,Zustand 虽然轻量,但在处理复杂的派生状态和异步流时,总觉得差那么点意思。就在这个当口,我在 GitHub 上偶然刷到了一个叫vurb.ts的仓库,来自一个叫vinkius-labs的组织。这个名字挺有意思,“Vurb”听起来像是 “Vibe”(氛围)和 “Verb”(动词)的结合体,而.ts后缀则明示了它的 TypeScript 血统。
简单来说,vurb.ts是一个旨在提供更直观、更符合现代 React 开发心智模型的状态管理库。它没有选择 Redux 那种严格的单向数据流和 action/reducer 模式,也没有完全照搬 Zustand 或 Jotai 的原子化思路,而是试图在声明式、响应式和类型安全之间找到一个更优雅的平衡点。它的核心卖点,从我初步探索来看,是极致的类型推断、基于 Proxy 的响应式追踪,以及一套旨在减少模板代码的 API 设计。如果你已经受够了在 action、reducer、selector 之间反复横跳,或者对现有方案的类型提示不够满意,那么vurb.ts值得你花上二十分钟了解一下。
这个库目前还处于比较早期的阶段,Star 数不算多,文档也偏向简洁,但这恰恰是探索新技术的好时机。它能解决我们日常开发中的哪些痛点?它的设计哲学是什么?实际用起来会不会有隐藏的坑?接下来,我就结合官方示例和自己的实验,带你深入拆解一下vurb.ts。
2. 核心设计哲学与架构解析
2.1 为何需要另一个状态管理库?
前端状态管理领域早已不是一片蓝海。从经典的 Redux,到轻量级的 Zustand、Jotai、Valtio,再到 React 官方的useContext配合useReducer,选择不可谓不多。那么vurb.ts的立足点在哪里?我认为它主要瞄准了以下几个痛点:
- 类型安全与开发体验的割裂:许多状态管理库虽然支持 TypeScript,但类型推断往往在复杂场景下失效,或者需要手动声明繁琐的类型。
vurb.ts将 TypeScript 作为一等公民,其 API 设计几乎能让 TypeScript 自动推断出所有类型,提供近乎完美的 IDE 自动补全和错误提示。 - 响应式更新的心智负担:在 React 中,触发重新渲染需要调用
setState或类似的更新函数。一些库(如 Valtio)利用 Proxy 实现了类似 Vue 的响应式,但可能与传统 React 模式有些差异。vurb.ts也采用了 Proxy,但它的目标是将响应式更新无缝集成到 React 的 Hook 模型中,让你用更“直接”的方式修改状态,同时保证渲染效率。 - 模板代码与抽象泄漏:Redux 的 action、reducer、middleware 固然清晰,但对于中小型应用来说,模板代码太多。Zustand 等库简化了这些,但有时为了性能优化(如细粒度订阅),又需要引入
select函数,这带来了额外的抽象层。vurb.ts试图提供一套更简洁、更直接的 API,减少你需要在“状态管理”本身上花费的思考。
2.2 核心架构:Store、Proxy 与 React 集成
vurb.ts的架构可以概括为三个核心部分:
- Store(存储):这是状态的容器,一个普通的 JavaScript 对象(或数组、Map 等)。但与普通对象不同,
vurb.ts会用 Proxy 包装它,从而能够追踪属性的读取(get)和设置(set)操作。 - Proxy(代理):这是实现响应式的魔法所在。当你通过
vurb.ts提供的 Hook(如useVurb)访问 store 时,你实际上拿到的是一个被 Proxy 包裹的版本。任何对该 Proxy 对象的属性访问都会被记录,任何对它的修改都会自动触发依赖于此属性的组件重新渲染。 - React Hook(集成层):
vurb.ts提供了自定义的 React Hook(主要是useVurb),用于在组件中“连接”到 store。这个 Hook 内部使用了useSyncExternalStore(React 18+)或类似的机制,来订阅 store 的变化,并在变化时调度组件更新。它负责将 Proxy 的响应式变化,翻译成 React 的渲染周期。
这种架构的优势在于,开发者可以用一种看似“可变”的方式操作状态(直接state.count++),而框架在背后自动、高效地处理了更新的追踪与组件的渲染。它模糊了“不可变更新”的显式操作,但通过 Proxy 保证了状态变化的可观测性和渲染的精确性。
注意:这种直接修改的方式可能会让习惯了 Redux 不可变更新的开发者感到不安。但请理解,这只是在 API 层面提供的便利,底层的数据流仍然是可预测的。
vurb.ts的 Proxy 会确保每次修改都产生一个新的引用(对于修改的部分),以满足 React 的渲染优化要求(如React.memo)。
2.3 与主流方案的对比
为了更清楚定位,我们快速对比一下:
| 特性 | Redux Toolkit (RTK) | Zustand | Jotai | Valtio | vurb.ts |
|---|---|---|---|---|---|
| 核心模式 | 单向数据流 (Action -> Reducer) | 可变 Store + Hook | 原子化状态 (Atomic) | 响应式 Proxy | 响应式 Proxy + 声明式 Hook |
| 不可变性 | 强制(Immer 辅助) | 可变 (但更新需用 set) | 可变 (但更新用 setter) | 可变(直接赋值) | 可变(直接赋值) |
| 类型安全 | 优秀 (需定义类型) | 优秀 | 优秀 | 良好 | 极佳(自动推断) |
| 模板代码量 | 多 | 少 | 少 | 极少 | 极少 |
| 学习成本 | 高 | 低 | 中 | 低 | 低-中(需理解 Proxy) |
| 适用场景 | 大型、复杂应用 | 中小型应用,快速开发 | 细粒度、衍生状态多 | 偏好响应式风格,简单应用 | 追求开发体验,强类型项目 |
vurb.ts在体验上最接近 Valtio,但它在与 React 的集成度和 TypeScript 的类型魔法上似乎走得更远。它的 API 设计更倾向于“只有一个推荐的使用方式”,减少了选择疲劳。
3. 从零开始:安装与基础使用
3.1 环境准备与安装
首先,确保你的项目是 React 16.8+(支持 Hook)和 TypeScript 4.5+(为了最佳类型体验)。然后通过 npm 或 yarn 安装:
npm install @vinkius-labs/vurb.ts # 或 yarn add @vinkius-labs/vurb.ts # 或 pnpm add @vinkius-labs/vurb.ts安装后,你不需要任何额外的 Provider 来包裹你的 React 应用根组件。这是它与Context方案的一个重要区别,意味着你可以更灵活地在任何组件中创建或使用 store。
3.2 创建你的第一个 Store
vurb.ts的核心是create函数。我们从一个经典的计数器例子开始:
// stores/counterStore.ts import { create } from '@vinkius-labs/vurb.ts'; // 使用 `create` 函数定义 store。初始状态是一个普通对象。 export const useCounterStore = create({ count: 0, name: 'My Counter', });是的,就这么简单。create函数接收一个初始状态对象,并返回一个Hook(useCounterStore),而不是一个 store 实例。这是vurb.ts的一个关键设计:Store 的创建和 React 的绑定是合二为一的。你导出的就是一个可以直接在组件中使用的 Hook。
3.3 在组件中使用:读取与更新
现在,在组件中使用这个 Hook:
// components/Counter.tsx import React from 'react'; import { useCounterStore } from '../stores/counterStore'; export const Counter: React.FC = () => { // 调用 Hook,获取整个 store 的响应式代理。 const store = useCounterStore(); const increment = () => { // 直接修改!这会被 Proxy 捕获,并触发组件重新渲染。 store.count += 1; }; const changeName = () => { // 同样,直接赋值。 store.name = `Counter Updated at ${Date.now()}`; }; return ( <div> <h1>{store.name}</h1> <p>Count: {store.count}</p> <button onClick={increment}>Increment</button> <button onClick={changeName}>Change Name</button> </div> ); };运行这个组件,点击按钮,你会发现状态更新和界面渲染完全符合预期。最关键的是,你不需要调用任何setState或set函数,直接对store对象的属性进行赋值或修改即可。vurb.ts的 Proxy 系统会追踪到store.count和store.name的访问,并在它们被修改时,只通知依赖于这些特定属性的组件进行更新。
实操心得:第一次这样写可能会感觉“不 React”,但它确实能工作,而且代码非常简洁。这种模式对于表单状态、UI 开关状态等局部但需要跨少量组件共享的场景尤其高效。
3.4 理解响应式追踪与渲染优化
vurb.ts的渲染优化是自动且细粒度的。看下面这个例子:
// components/UserProfile.tsx const UserProfile = () => { const store = useUserStore(); // 假设 store 有 `user` 对象,包含 `name`, `age`, `address` 等属性 // 组件A:只依赖于 user.name const ComponentA = () => { const store = useUserStore(); console.log('ComponentA renders'); return <div>Name: {store.user.name}</div>; }; // 组件B:只依赖于 user.age const ComponentB = () => { const store = useUserStore(); console.log('ComponentB renders'); return <div>Age: {store.user.age}</div>; }; const updateName = () => { store.user.name = 'New Name'; }; const updateAge = () => { store.user.age += 1; }; return ( <div> <ComponentA /> <ComponentB /> <button onClick={updateName}>Update Name</button> <button onClick={updateAge}>Update Age</button> </div> ); };当你点击 “Update Name” 按钮时,只有ComponentA会重新渲染,ComponentB不会。这是因为vurb.ts的 Proxy 精确地知道ComponentA订阅了store.user.name,而ComponentB订阅了store.user.age。这种自动的依赖收集和细粒度更新是它性能优势的关键,你无需手动编写select函数来优化。
4. 进阶特性与模式探索
4.1 计算属性(Derived State)
在实际应用中,我们经常需要从基础状态派生出新的状态。vurb.ts通过computed函数来优雅地处理这种情况。
// stores/todoStore.ts import { create, computed } from '@vinkius-labs/vurb.ts'; export const useTodoStore = create({ todos: [ { id: 1, text: 'Learn vurb.ts', completed: true }, { id: 2, text: 'Build a project', completed: false }, { id: 3, text: 'Write a blog', completed: false }, ], filter: 'all', // 'all', 'active', 'completed' }); // 定义计算属性 export const useFilteredTodos = computed( // 第一个参数:依赖的 store Hook useTodoStore, // 第二个参数:派生函数,其返回值就是计算属性的值 (store) => { switch (store.filter) { case 'active': return store.todos.filter(todo => !todo.completed); case 'completed': return store.todos.filter(todo => todo.completed); default: return store.todos; } } ); export const useTodoStats = computed(useTodoStore, (store) => ({ total: store.todos.length, completed: store.todos.filter(t => t.completed).length, active: store.todos.filter(t => !t.completed).length, }));在组件中使用计算属性:
// components/TodoList.tsx import { useTodoStore, useFilteredTodos, useTodoStats } from '../stores/todoStore'; const TodoList = () => { const store = useTodoStore(); const filteredTodos = useFilteredTodos(); // 像 Hook 一样调用 const stats = useTodoStats(); return ( <div> <div>Total: {stats.total}, Active: {stats.active}, Completed: {stats.completed}</div> <select value={store.filter} onChange={(e) => { store.filter = e.target.value; }}> <option value="all">All</option> <option value="active">Active</option> <option value="completed">Completed</option> </select> <ul> {filteredTodos.map(todo => ( <li key={todo.id}> <input type="checkbox" checked={todo.completed} onChange={() => { // 直接找到并修改 const target = store.todos.find(t => t.id === todo.id); if (target) target.completed = !target.completed; }} /> {todo.text} </li> ))} </ul> </div> ); };computed返回的也是一个 Hook。它的强大之处在于:
- 自动依赖追踪:
computed函数内部对store的访问会被自动追踪。只有当store.todos或store.filter变化时,useFilteredTodos才会重新计算。 - 记忆化(Memoization):计算结果是缓存的。在依赖未变化时,多次调用
useFilteredTodos()会返回相同的引用,避免不必要的重计算和子组件重渲染。 - 完美的类型推断:
filteredTodos的类型会自动推断为Todo[],stats的类型是{ total: number; completed: number; active: number },完全无需手动声明。
4.2 异步操作与副作用
状态管理离不开异步操作。vurb.ts没有规定固定的异步处理模式(如 Redux Thunk/Saga),而是鼓励你将异步逻辑放在 store 外部,或者作为 store 的一个方法。这里推荐一种清晰的模式:
// stores/authStore.ts import { create } from '@vinkius-labs/vurb.ts'; export interface User { id: string; email: string; name: string; } export const useAuthStore = create({ user: null as User | null, loading: false, error: null as string | null, }); // 定义异步 action(只是一个普通函数,操作 store) export const authActions = { async login(credentials: { email: string; password: string }) { const store = useAuthStore(); // 注意:在函数中调用 Hook! // 但这里有个问题:`useAuthStore` 是一个 Hook,只能在 React 组件或自定义 Hook 中调用。 // 所以我们需要另一种方式。 }, };直接在非 React 函数中调用useAuthStore()会违反 React 的规则。vurb.ts提供了getStore工具来解决这个问题。
// stores/authStore.ts (修正版) import { create, getStore } from '@vinkius-labs/vurb.ts'; export const useAuthStore = create({ user: null as User | null, loading: false, error: null as string | null, }); // 获取 store 的“静态”引用,用于在非 React 上下文中操作状态。 const authStore = getStore(useAuthStore); export const authActions = { async login(credentials: { email: string; password: string }) { // 1. 开始加载 authStore.loading = true; authStore.error = null; try { // 2. 执行异步请求 const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials), }); const userData: User = await response.json(); if (!response.ok) throw new Error('Login failed'); // 3. 更新状态 authStore.user = userData; authStore.error = null; } catch (err: any) { // 4. 处理错误 authStore.error = err.message || 'Login error'; } finally { // 5. 结束加载 authStore.loading = false; } }, logout() { authStore.user = null; // 可能还需要调用清理 API }, };在组件中,你可以这样使用:
// components/LoginForm.tsx import { useAuthStore, authActions } from '../stores/authStore'; const LoginForm = () => { const auth = useAuthStore(); // 获取响应式 store const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.target as HTMLFormElement); const credentials = { email: formData.get('email') as string, password: formData.get('password') as string, }; await authActions.login(credentials); }; if (auth.loading) return <div>Logging in...</div>; if (auth.error) return <div>Error: {auth.error}</div>; return ( <form onSubmit={handleSubmit}> <input name="email" type="email" /> <input name="password" type="password" /> <button type="submit">Login</button> </form> ); };这种模式将异步逻辑与状态更新清晰地分离。authActions是一个纯逻辑模块,负责协调异步操作和修改 store。组件只负责触发 action 和消费状态。getStore是关键,它让你能在 React 上下文之外安全地读写 store。
注意事项:
getStore返回的是 store 的原始对象(未被 Proxy 包装),在 action 中修改它同样会触发响应式更新。但要确保不要在 React 渲染周期内调用getStore并修改状态,这可能导致意外的渲染行为。最好只在事件处理函数、useEffect 回调或异步流程中使用。
4.3 处理嵌套对象与数组
得益于 Proxy,vurb.ts对嵌套对象和数组的处理是“深度响应式”的。
const store = useNestedStore(); // 直接修改深层属性 store.settings.theme = 'dark'; store.items.push({ id: 4, name: 'new item' }); store.items[0].name = 'updated';所有这些操作都会触发正确的更新。但是,有一个非常重要的细节:如果你直接替换整个嵌套对象或数组,其内部的响应式连接会丢失。
// 假设 store.user 是一个响应式对象 store.user = { ...store.user, name: 'New Name' }; // 正确:新对象会被自动包装为响应式 store.user = someNewUserObject; // 正确 // 但是,如果你从其他地方拿到一个对象并赋值给深层属性,需要确保它是响应式的吗? // 实际上,vurb.ts 会在赋值时自动用 Proxy 包装新值。所以大多数情况下是安全的。 const newSettings = { theme: 'light', fontSize: 14 }; store.settings = newSettings; // newSettings 会被自动转换为响应式代理对于数组,类似map,filter,slice等返回新数组的方法,赋值后新数组也会被自动代理。所以你可以安全地使用不可变更新模式:
// 添加项 store.todos = [...store.todos, newTodo]; // 删除项 store.todos = store.todos.filter(t => t.id !== idToRemove); // 更新项 store.todos = store.todos.map(t => t.id === idToUpdate ? { ...t, completed: true } : t);实操心得:虽然直接修改(
push,splice, 直接属性赋值)很方便,但在涉及复杂逻辑或需要保留操作历史(如撤销/重做)时,采用返回新引用的不可变模式更可控。vurb.ts对两种风格都支持得很好。
5. 工程化实践与性能考量
5.1 如何组织大型应用的 Store?
对于小型应用,一个 store 文件可能就够了。但对于大型应用,建议按功能模块拆分:
src/ stores/ auth.store.ts // 认证相关状态 user.store.ts // 用户资料、偏好 product.store.ts // 产品、商品数据 cart.store.ts // 购物车 ui.store.ts // UI 全局状态(侧边栏、弹窗) index.ts // 统一导出每个 store 文件使用create定义自己的 Hook 和相关的 actions、computed properties。在index.ts中统一导出,方便导入:
// stores/index.ts export { useAuthStore, authActions } from './auth.store'; export { useUserStore, userActions } from './user.store'; export { useProductStore, productComputed } from './product.store'; // ...如果 store 之间需要相互访问,可以使用getStore在 action 或 computed 函数中获取另一个 store 的引用。但要谨慎处理循环依赖。
5.2 性能优化与陷阱
vurb.ts的自动细粒度更新在大多数情况下性能很好。但仍需注意以下几点:
避免在渲染函数中创建新对象/函数:这是一个通用的 React 优化原则,在
vurb.ts中同样适用。如果将一个在每次渲染时都新建的对象或函数赋值给 store,会导致不必要的依赖追踪和子组件重渲染。// 不推荐 const Component = () => { const store = useMyStore(); store.someConfig = { foo: 'bar' }; // 每次渲染都赋值新对象 // ... }; // 推荐:在 useEffect 或事件处理中赋值,或使用 useMemo 记忆化配置大型列表的渲染:当 store 中有一个包含数千项的数组,并且列表项组件直接订阅了整个数组或数组中的对象时,修改其中一项会触发所有列表项重新检查依赖(虽然可能不都重渲染)。对于超大型列表,考虑使用虚拟滚动库(如
react-window),并确保列表项组件通过computed或精细化的选择器只订阅它们真正需要的部分数据。computed的代价:虽然computed有缓存,但复杂的计算函数本身执行可能耗时。确保computed函数是纯函数,且逻辑不过于沉重。对于极其昂贵的计算,可以考虑使用useMemo配合 store 状态在组件层面进行优化。getStore的使用时机:只在需要的时候使用getStore,例如在异步 action 中。在组件内部,始终使用useStore()Hook,这样才能建立正确的响应式订阅关系。
5.3 服务端渲染 (SSR) 与持久化
vurb.ts作为一个客户端状态管理库,对 SSR 没有内置的特殊处理。在 Next.js 等框架中,你需要确保 store 的初始化在客户端和服务器端是一致的,并且避免在服务器端渲染时将带有状态的 store 序列化到 HTML 中(这可能导致水合错误)。
一个常见的模式是,在 store 创建时检查是否在浏览器环境中,并从一个全局变量或localStorage中初始化状态(用于持久化)。
// stores/settings.store.ts import { create } from '@vinkius-labs/vurb.ts'; // 一个简单的持久化工具函数 const loadFromLocalStorage = <T>(key: string, defaultValue: T): T => { if (typeof window === 'undefined') return defaultValue; try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : defaultValue; } catch { return defaultValue; } }; const saveToLocalStorage = (key: string, value: any) => { if (typeof window === 'undefined') return; try { window.localStorage.setItem(key, JSON.stringify(value)); } catch (e) { console.error('Failed to save to localStorage', e); } }; const initialSettings = loadFromLocalStorage('app-settings', { theme: 'light', language: 'en', notifications: true, }); export const useSettingsStore = create(initialSettings); // 订阅 store 变化并自动持久化(简单示例,生产环境需防抖) if (typeof window !== 'undefined') { // 这里需要一种方式来监听 store 变化。vurb.ts 本身可能不提供直接的事件监听。 // 一种替代方案是在修改 store 的 action 中显式调用持久化。 }对于更复杂的 SSR 集成和持久化,社区可能未来会提供相应的中间件或适配器。目前,需要开发者根据项目需求自行实现。
6. 常见问题与排查实录
在实际使用和测试vurb.ts的过程中,我遇到并总结了一些典型问题。
6.1 类型推断不工作或报错?
确保你使用的是足够新版本的 TypeScript(>=4.5)。检查你的tsconfig.json中strict模式或相关严格类型检查选项是否开启。vurb.ts严重依赖 TypeScript 的高级类型特性。如果类型仍然奇怪,尝试显式定义 store 的接口,然后作为泛型参数传给create。
interface CounterState { count: number; name: string; } // 显式提供类型(通常自动推断就足够了) export const useCounterStore = create<CounterState>({ count: 0, name: 'Counter', });6.2 修改了状态,但组件没有更新?
- 检查是否直接修改了
getStore返回的对象?在组件中,你必须使用useStore()返回的响应式代理。如果你错误地在组件渲染函数中使用了getStore(someStoreHook)并修改它,React 的订阅关系没有建立,所以不会更新。 - 检查修改的层级:确保你是通过响应式代理进行修改的。例如,如果你从 store 中解构了一个对象,然后修改这个解构后的变量,是无效的。
// 错误 const { user } = useAuthStore(); user.name = 'New'; // 这不会触发更新,因为 `user` 是解构出的值,不是代理 // 正确 const store = useAuthStore(); store.user.name = 'New'; // 通过代理修改 - 检查异步更新:在异步回调(如
setTimeout,Promise.then)中修改状态是有效的,因为 Proxy 的拦截是同步的。但如果更新发生在 React 的渲染批次之外,React 18 的并发特性可能需要用unstable_batchedUpdates包裹(不过vurb.ts内部应该处理了)。
6.3 在 StrictMode 下开发,控制台有警告?
React 的 StrictMode 会故意双重调用组件函数和 Hook,以帮助发现副作用。vurb.ts的create函数应该是在每次调用 Hook 时返回相同的 store 实例,所以通常是安全的。但如果看到关于“内存泄漏”或“组件卸载后更新状态”的警告,检查你的副作用(如useEffect中的定时器、订阅)是否在清理函数中正确被清除。这些警告通常与vurb.ts本身无关,而是你的副作用逻辑问题。
6.4 如何调试 Store 的变化?
由于状态是直接修改的,传统的“action 日志”模式不直接适用。你可以利用 Proxy 的特性,或者在 store 创建后包装一层监听:
import { create, getStore } from '@vinkius-labs/vurb.ts'; const initialState = { count: 0 }; const baseStore = create(initialState); // 开发环境:包装 store 的修改函数(如果需要)或使用 Proxy 的 handler 进行调试 // 一个简单的方法是 monkey-patch `getStore` 返回的对象(不推荐用于生产) if (process.env.NODE_ENV === 'development') { const originalStore = getStore(baseStore); const handler = { set(target, property, value) { console.log(`[Store Update] ${String(property)}:`, target[property], '->', value); target[property] = value; return true; // 表示设置成功 }, }; // 注意:这只是一个思路,实际实现需要更严谨,并考虑嵌套对象。 // vurb.ts 可能在未来版本提供官方的开发工具。 } export const useMyStore = baseStore;更实用的方法是使用浏览器的 DevTools。因为状态是普通对象,你可以在组件中打印store,或者利用 React DevTools 检查组件的 props 和 state(虽然 store 不是 props 或 state,但 Hook 的值可以查看)。
6.5 与 React 状态 (useState,useReducer) 如何共存?
完全没有问题。vurb.ts管理的是全局或跨组件的共享状态。组件内部的私有、临时状态,仍然应该使用useState。例如,一个表单控件的临时输入值,在提交前不需要共享,就用useState。当提交后需要将数据同步到全局 store 时,再调用相应的 action 修改vurb.ts的 store。
选择策略:
useState:组件私有、生命周期短暂、不需要与其他组件同步的状态。useReducer:组件内部复杂状态逻辑,但仍然是组件私有的。vurb.ts(或任何状态库):需要在多个不直接关联的组件之间共享、持久化、或者与服务器状态同步的状态。
vurb.ts的出现不是为了取代 React 内置状态,而是为了在共享状态这个场景下,提供一个类型更安全、写法更简洁的补充方案。经过几天的试用,我认为它特别适合那些对开发体验有较高要求、项目大量使用 TypeScript、且希望状态管理代码尽可能少的中大型 React 应用。它的学习曲线平缓,一旦习惯了直接修改的响应式风格,开发效率会有明显的提升。当然,在团队中引入时需要确保成员都理解其背后的 Proxy 原理,避免一些常见的误用。
