Valtio
基于 Proxy 的响应式状态管理——像操作普通对象一样修改状态,自动追踪依赖、精确订阅、最小化重渲染。
Valtio 通过 JavaScript Proxy 实现"修改即更新"的响应式体验,核心 API 仅 proxy()、useSnapshot()、subscribe() 三个函数,gzip 后约 3KB。采用写 proxy 读 snapshot 分离模型,与 Zustand、Jotai 同属 pmndrs 生态,适合偏好可变更新风格的团队。
Valtio
基于 Proxy 的响应式状态管理——像操作普通对象一样修改状态,自动追踪依赖、精确订阅、最小化重渲染,让 React 状态管理"像魔法一样简单"。
技术简介说明
Valtio 是由 pmndrs 维护的响应式状态管理库,同样由 Daishi Kato 设计(与 Zustand、Jotai 同一作者)。它的核心理念是Proxy-based Mutable State——通过 JavaScript 的 Proxy 对象包装普通 JavaScript 对象,自动追踪属性读写,实现"修改即更新"的响应式体验。
与 Zustand 的"不可变 + set()"模式截然不同,Valtio 走的是可变状态 + 自动追踪路线:你直接修改对象属性(state.count++),Proxy 自动感知变化,只通知订阅了该属性的组件重渲染。这种体验类似 MobX 和 Vue 的响应式系统,但体积只有约 3 kB,API 只有 proxy()、useSnapshot()、subscribe() 三个核心函数。
Valtio v2 于 2024 年 8 月发布,带来了 React 19 的 use() Hook 兼容、架构优化等重要改进。截至 2026 年 7 月,Valtio 最新版本为 v2.3.2,GitHub 星标超过 10.2k,npm 周下载量约 160 万次。虽然社区规模小于 Zustand,但 Valtio 在"偏好可变更新语法"的开发者群体中保持着稳定的采用率,特别适合从 MobX 或 Vue 迁移而来的团队。
基本信息
| 项目 | 信息 |
|---|---|
| 官网 | https://valtio.dev |
| GitHub | https://github.com/pmndrs/valtio |
| npm | https://www.npmjs.com/package/valtio |
| 最新版本 | v2.3.2(2026-05-01 发布) |
| License | MIT |
| GitHub Stars | ~10.2k |
| 周下载量 | ~160 万 |
| Bundle Size | ~3 kB(gzip) |
| TypeScript | 原生支持,源码 95.8% TypeScript |
| 主要维护者 | Daishi Kato(@dai_shi) |
| 所属组织 | pmndrs |
| Node.js 要求 | >= 18 |
| React 要求 | >= 18(完整支持 React 19) |
快速上手
安装
# npm
npm install valtio
# yarn
yarn add valtio
# pnpm
pnpm add valtio
# bun
bun add valtio基础配置
Valtio 不需要 Provider、不需要 Context、不需要任何配置。创建 proxy 对象即可在组件中使用:
import { proxy, useSnapshot } from 'valtio'
// 1. 创建 proxy 状态(像普通对象一样)
const state = proxy({
count: 0,
name: 'Valtio',
})
// 2. 在组件中使用 useSnapshot 读取(自动追踪依赖)
function Counter() {
const snap = useSnapshot(state)
return (
<div>
<p>Count: {snap.count}</p>
<button onClick={() => state.count++}>+1</button>
</div>
)
}最小示例
import { proxy, useSnapshot, subscribe } from 'valtio'
// 1. 创建 proxy 状态
const state = proxy({
todos: [],
filter: 'all',
})
// 2. 直接修改(可变更新,无需 set/immutable)
function addTodo(text) {
state.todos.push({ id: Date.now(), text, done: false })
}
function toggleTodo(id) {
const todo = state.todos.find((t) => t.id === id)
if (todo) todo.done = !todo.done // 直接修改嵌套属性
}
// 3. 组件中自动响应(只重渲染依赖了变化属性的组件)
function TodoList() {
const snap = useSnapshot(state)
const filtered = snap.todos.filter((t) => {
if (snap.filter === 'active') return !t.done
if (snap.filter === 'done') return t.done
return true
})
return (
<div>
<input
placeholder="New todo"
onKeyDown={(e) => {
if (e.key === 'Enter') {
addTodo(e.currentTarget.value)
e.currentTarget.value = ''
}
}}
/>
<select value={snap.filter} onChange={(e) => (state.filter = e.target.value)}>
<option value="all">All</option>
<option value="active">Active</option>
<option value="done">Done</option>
</select>
<ul>
{filtered.map((todo) => (
<li key={todo.id} onClick={() => toggleTodo(todo.id)}>
{todo.text} {todo.done ? '✅' : ''}
</li>
))}
</ul>
</div>
)
}
// 4. 组件外部也能订阅变化
subscribe(state, () => {
console.log('State changed:', state)
})核心概念与架构
Proxy 响应式模型
Valtio 的核心是 JavaScript 的 Proxy API。当你调用 proxy(obj) 时,Valtio 返回一个代理对象,该代理:
- 拦截属性读取(
gettrap)— 自动记录当前正在读取该属性的组件 - 拦截属性写入(
settrap)— 自动通知订阅了该属性的组件重渲染 - 递归代理(deep proxy)— 嵌套对象也会被自动代理
┌─────────────────────────────────────────┐
│ Valtio 响应式架构 │
│ │
│ ┌──────────────────────────────────┐ │
│ │ proxy(state) │ │
│ │ ┌─────────┐ ┌──────────────┐ │ │
│ │ │ 原始对象 │ │ Proxy 代理层 │ │ │
│ │ │ { ... } │──│ get / set │ │ │
│ │ └─────────┘ └──────┬───────┘ │ │
│ │ │ │ │
│ │ ┌─────────────▼──────┐ │ │
│ │ │ 依赖追踪系统 │ │ │
│ │ │ (谁读了什么属性) │ │ │
│ │ └─────────────┬──────┘ │ │
│ └──────────────────────┼──────────┘ │
│ │ │
│ ┌───────────────▼────────┐ │
│ │ useSnapshot(proxy) │ │
│ │ ┌──────────────────┐ │ │
│ │ │ 不可变快照 │ │ │
│ │ │ (React 安全读取) │ │ │
│ │ └──────────────────┘ │ │
│ └────────────────────────┘ │
│ │
│ subscribe(proxy, callback) │
│ → 组件外部也能监听变化 │
└─────────────────────────────────────────┘
Snapshot 与 Proxy 分离
Valtio 采用 write-proxy / read-snapshot 分离模型:
- 写入 通过
proxy对象(可变操作):state.count++ - 读取 通过
useSnapshot(proxy)返回的不可变快照
这种分离解决了 React 渲染一致性的重要问题:组件读取的 snapshot 是不可变的,确保同一次渲染中状态不会中途变化。而写入操作通过 Proxy 自动触发下一轮更新。
微订阅(Micro-Subscriptions)
Valtio 的依赖追踪是属性级别的。组件只在它实际读取的属性变化时才重渲染:
const state = proxy({ count: 0, name: 'Valtio' })
function Counter() {
const snap = useSnapshot(state)
return <p>{snap.count}</p> // 只有 count 变化时重渲染
}
function Name() {
const snap = useSnapshot(state)
return <p>{snap.name}</p> // 只有 name 变化时重渲染
}核心特性
1. Proxy 可变更新
不需要 set()、不需要展开运算符、不需要不可变思维。直接修改对象属性,Proxy 自动追踪:
state.count++
state.user.name = 'Alice' // 深层嵌套也能追踪
state.items.push({ id: 1 })2. 自动依赖追踪
无需手动指定 selector,Valtio 通过 Proxy 的 get trap 自动记录组件读取了哪些属性,只在相关属性变化时触发重渲染。
3. Snapshot 不可变读取
useSnapshot() 返回不可变快照,确保 React 渲染过程中的数据一致性。写入通过 proxy,读取通过 snapshot,完美配合 React 的并发渲染。
4. 零样板代码
不需要 action creators、reducer、dispatch、Provider。创建 proxy 对象后直接在组件中使用。
5. Vanilla JS 支持
Valtio 可以完全脱离 React 使用(valtio/vanilla),适合 Vue、Svelte 或纯 JavaScript 场景:
import { proxy, subscribe } from 'valtio/vanilla'
const state = proxy({ count: 0 })
subscribe(state, () => {
document.getElementById('count').textContent = state.count
})6. React 19 use() Hook 兼容
Valtio v2 兼容 React 19 的 use() Hook,支持在组件中直接处理异步数据:
import { use } from 'react'
import { proxy, useSnapshot } from 'valtio'
const state = proxy({
dataPromise: fetch('/api/data').then((r) => r.json()),
})
function DataDisplay() {
const snap = useSnapshot(state)
const data = use(snap.dataPromise) // React 19 use() Hook
return <p>{data.message}</p>
}7. 派生状态(derive 工具)
通过 derive 工具函数创建计算属性,类似 MobX 的 computed:
import { proxy, useSnapshot } from 'valtio'
import { derive } from 'valtio/utils'
const state = proxy({
items: [1, 2, 3, 4, 5],
filter: 'all',
})
const derived = derive({
activeItems: (get) => {
const items = get(state).items
const filter = get(state).filter
return items.filter((i) => i > 2)
},
totalCount: (get) => get(state).items.length,
})8. 持久化支持
通过 snapshotWithEquality 和社区中间件,可以实现状态的本地持久化,支持 localStorage、IndexedDB 等后端。
9. 类实例支持
Proxy 支持 class 实例作为状态,可以封装业务逻辑:
class CounterModel {
count = 0
increment() {
this.count++
}
}
const state = proxy(new CounterModel())10. 同事件批次通知
在同一事件 tick 内的多次修改会被批次化为一次通知,避免不必要的中间重渲染。
生态图
Valtio 生态
│
┌──────────────────────┼──────────────────────┐
│ │ │
核心 API 工具库 集成方案
│ │ │
├─ proxy() ├─ valtio/utils ├─ React DOM
├─ useSnapshot() │ ├─ derive ├─ React Native
├─ subscribe() │ ├─ proxyWithHistory │─ React Three Fiber
├─ snapshot() │ └─ ref ├─ Lynx.js
├─ ref() ├─ valtio/vanilla ├─ Waku
│ │ ├─ Next.js
官方中间件 │ └─ Remix
│ │
├─ proxyWithHistory │
└─ derive │
│
社区扩展
│
├─ valtio-persist
├─ valtio-form
└─ valtio-sync
核心包结构
| 包/模块 | 说明 |
|---|---|
valtio | 核心库(React 集成) |
valtio/vanilla | 非 React 环境的纯 JS API |
valtio/utils | 工具函数(derive、proxyWithHistory、ref 等) |
valtio/macro | 宏工具(实验性) |
适用场景
1. 偏好可变更新语法的团队
如果你的团队习惯 Vue、MobX 或直接修改对象的方式管理状态,Valtio 的 Proxy 模型比 Zustand 的 set() 更自然直观。
2. 频繁深层嵌套更新
当状态结构深层嵌套且需要频繁修改时,Valtio 的可变语法比不可变展开(spread)更简洁:
// Valtio:直接修改
state.users[0].profile.name = 'Alice'
// Zustand:需要展开
set((s) => ({
users: s.users.map((u, i) =>
i === 0 ? { ...u, profile: { ...u.profile, name: 'Alice' } } : u
),
}))
// 或借助 Immer 中间件3. 从 MobX 迁移的项目
Valtio 提供了类似 MobX 的响应式体验(自动追踪、可观察对象),但体积更小(3 kB vs 16 kB)、API 更简单、无装饰器依赖。
4. React 组件外的状态订阅
subscribe() API 使得在 React 组件外部(API 拦截器、WebSocket 回调、工具函数)监听状态变化非常方便。
5. 细粒度响应式场景
Valtio 的属性级依赖追踪天然适合需要精细控制重渲染范围的应用——只有实际读取了变化属性的组件才会重渲染。
6. 非 React 环境的响应式
通过 valtio/vanilla,Valtio 可以在 Vue、Svelte、纯 DOM 或 Web Components 中使用,提供统一的响应式状态管理。
7. 游戏 / 3D / 高频更新应用
Valtio 的 Proxy 追踪 + snapshot 读取模型在 React Three Fiber 等高频渲染场景中表现良好,避免不必要的 React reconciliation。
开发与工程化
TypeScript 配置
import { proxy, useSnapshot } from 'valtio'
// 类型推断:proxy() 自动推断类型
interface AppState {
count: number
user: {
name: string
age: number
}
todos: Array<{ id: number; text: string; done: boolean }>
}
const state = proxy<AppState>({
count: 0,
user: { name: '', age: 0 },
todos: [],
})
// useSnapshot 返回只读的 snapshot 类型
function App() {
const snap = useSnapshot(state)
// snap.count 是 number (只读)
// snap.user.name 是 string (只读)
return <div>{snap.count}</div>
}派生状态
import { proxy, useSnapshot } from 'valtio'
import { derive } from 'valtio/utils'
const state = proxy({
items: [
{ id: 1, text: 'Learn Valtio', done: true },
{ id: 2, text: 'Build app', done: false },
],
filter: 'all' as 'all' | 'active' | 'done',
})
// derive 创建计算属性
const derived = derive({
filteredItems: (get) => {
const { items, filter } = get(state)
switch (filter) {
case 'active': return items.filter((i) => !i.done)
case 'done': return items.filter((i) => i.done)
default: return items
}
},
activeCount: (get) => get(state).items.filter((i) => !i.done).length,
})
function TodoList() {
const { filteredItems, activeCount } = useSnapshot(derived)
return (
<div>
<p>{activeCount} items left</p>
<ul>
{filteredItems.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
</div>
)
}持久化
import { proxy, useSnapshot, subscribe } from 'valtio'
const state = proxy({ count: 0 })
// 从 localStorage 恢复
const saved = localStorage.getItem('count')
if (saved) state.count = JSON.parse(saved)
// 监听变化并持久化
subscribe(state, () => {
localStorage.setItem('count', JSON.stringify(state.count))
})测试
import { proxy, snapshot, subscribe } from 'valtio'
test('proxy state updates', () => {
const state = proxy({ count: 0 })
state.count++
expect(state.count).toBe(1)
// snapshot 返回不可变副本
const snap = snapshot(state)
expect(snap.count).toBe(1)
})
test('subscribe fires on changes', () => {
const state = proxy({ count: 0 })
const callback = vi.fn()
subscribe(state, callback)
state.count++
// 同一事件 tick 内的多次修改批次化为一次通知
expect(callback).toHaveBeenCalledTimes(1)
})性能与安全
性能特性
| 维度 | 表现 |
|---|---|
| Bundle Size | ~3 kB(gzip),约为 Redux 的 1/4 |
| 重渲染优化 | 属性级依赖追踪,只重渲染实际读取了变化属性的组件 |
| 写入性能 | Proxy 拦截有轻微开销(约 5-10%),但实际场景差异可忽略 |
| 内存占用 | 低,Proxy 对象共享底层引用 |
| 并发安全 | snapshot 不可变读取,完整支持 React 18+ 并发模式 |
| 批次更新 | 同事件 tick 内的多次修改自动批次化 |
Proxy 性能注意事项
// ✅ 直接修改属性(Proxy 自动追踪)
state.count++
state.user.name = 'Alice'
// ❌ 重新赋值根变量(破坏追踪)
let state = proxy({ count: 0 })
state = proxy({ count: 1 }) // 错误!根变量重新赋值会丢失追踪
// ✅ 正确做法:修改属性
const state = proxy({ count: 0 })
state.count = 1 // 正确安全注意事项
- 避免不可序列化对象:Proxy 不应包裹 DOM 节点、Map、Set 等不可序列化的对象,这可能导致内存泄漏或追踪异常。
- Snapshot 安全性:
useSnapshot()返回的快照是只读的,尝试修改会抛出错误。这确保了 React 渲染的不可变性。 - 避免根变量重新赋值:
const state = proxy({...})之后不能对state变量重新赋值,否则 Proxy 追踪链断裂。 - Class 实例:Proxy 完整支持 class 实例,但需要确保实例方法是可枚举的或通过原型链正确继承。
- 循环引用:Proxy 对循环引用的处理需要注意,过深的递归追踪可能导致性能问题。
技术对比
横向对比表
| 特性 | Valtio | Zustand | Jotai | MobX | Redux Toolkit | Recoil |
|---|---|---|---|---|---|---|
| 模型 | Proxy 可变 | 单 Store 不可变 | 原子化 | Observable 可变 | 单 Store 不可变 | 原子化 |
| 更新方式 | 直接修改 | set() 函数 | atom setter | 直接修改 | dispatch | atom setter |
| Bundle Size | ~3 kB | ~1.1 kB | ~4 kB | ~16 kB | ~11 kB | ~14 kB |
| 学习曲线 | ⭐ 极低 | ⭐ 极低 | ⭐⭐ 低 | ⭐⭐⭐ 中高 | ⭐⭐⭐ 中等 | ⭐⭐⭐ 中等 |
| 依赖追踪 | 自动 (Proxy) | 手动 (selector) | 自动 (atom 依赖) | 自动 (Observable) | 手动 (selector) | 自动 (atom 依赖) |
| Provider | 不需要 | 不需要 | 不需要 | 不需要 | 需要 | 需要 |
| TypeScript | 良好 | 优秀 | 优秀 | 优秀 | 优秀 | 良好 |
| DevTools | Chrome Extension | Redux DevTools | 独立 DevTools | MobX DevTools | Redux DevTools | Recoil DevTools |
| 不可变/可变 | 写入可变 / 读取不可变 | 不可变 | 不可变 | 可变 | 不可变 | 不可变 |
| 派生状态 | derive 工具 | 手动 selector | atom 派生 | computed | reselect | selectorFamily |
| SSR | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ 有限 |
| React Native | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 并发模式 | ✅ | ✅ | ✅ | ⚠️ | ✅ | ⚠️ |
| 维护状态 | 活跃 | 活跃 | 活跃 | 活跃 | 活跃 | 已归档 |
| 周下载量 (2026) | ~160 万 | ~3600 万 | ~530 万 | ~250 万 | ~600 万 | — |
关键差异:Valtio vs Zustand
| 对比维度 | Valtio | Zustand |
|---|---|---|
| 更新语法 | state.count++(直接可变) | set((s) => ({ count: s.count + 1 }))(不可变) |
| 依赖追踪 | 自动(Proxy get trap) | 手动(selector 函数) |
| 心智模型 | "像 Vue/MobX 一样直接改" | "像 Redux 一样不可变更新" |
| 深层更新 | 天然简洁 | 需要展开或 Immer |
| 调试 | 修改分散在各处 | 集中在 set() 调用 |
| 时间旅行 | 需要额外工具 | 通过 Redux DevTools |
| 适合人群 | Vue/MobX 迁移者 | Redux 迁移者 / 函数式偏好者 |
选型建议
- Valtio — 偏好可变更新语法、不想学不可变思维、从 MobX/Vue 迁移的团队。深层嵌套状态更新特别多时优势明显。
- Zustand — 大多数项目的默认选择。不可变模型更利于调试和预测。
- Jotai — 需要原子化组合、派生状态链的复杂场景。
- MobX — 已有 MobX 代码库继续使用;新项目如果不需要 MobX 的完整生态,Valtio 是更轻量的替代。
- Redux Toolkit — 大团队需要严格规范和完整 DevTools。
最佳实践
1. 始终使用 useSnapshot 读取
// ✅ 正确:通过 useSnapshot 读取
const snap = useSnapshot(state)
return <p>{snap.count}</p>
// ❌ 错误:直接读取 proxy 对象
return <p>{state.count}</p> // 不会触发重渲染!2. 写入通过 Proxy,读取通过 Snapshot
// ✅ 写入:通过 proxy 对象
const onClick = () => { state.count++ }
// ✅ 读取:通过 snapshot
const snap = useSnapshot(state)
return <p>{snap.count}</p>
// ❌ 不要在 snapshot 上写入
// snap.count++ // 报错:snapshot 是只读的3. 避免根变量重新赋值
const state = proxy({ count: 0 })
// ❌ 错误:根变量重新赋值
state = proxy({ count: 1 }) // 丢失追踪
// ✅ 正确:修改属性
state.count = 1
// ✅ 正确:使用 Object.assign
Object.assign(state, { count: 1, name: 'new' })4. 使用 derive 创建派生状态
import { derive } from 'valtio/utils'
// ✅ 使用 derive 替代手动维护派生值
const state = proxy({ items: [], tax: 0.1 })
const derived = derive({
total: (get) => get(state).items.reduce((sum, i) => sum + i.price, 0),
totalWithTax: (get) => get(derived).total * (1 + get(state).tax),
})5. 组件外使用 subscribe
// 在组件外部监听状态变化(日志、持久化、同步)
const unsub = subscribe(state, () => {
localStorage.setItem('app-state', JSON.stringify(snapshot(state)))
})
// 清理订阅
unsub()6. 使用 ref 排除不需要追踪的属性
import { proxy, ref } from 'valtio'
const state = proxy({
count: 0,
// ref() 包裹的对象不会被 Proxy 追踪
// 适合存储 DOM 引用、第三方库实例等
editor: ref(null),
canvas: ref(null),
})7. 与 Immer 的区别
Valtio 和 Immer 都支持可变语法更新状态,但定位不同:
- Valtio:完整的响应式状态管理方案(追踪 + 订阅 + 渲染集成)
- Immer:纯不可变更新工具(只在 set() 内使用)
- 两者可以结合使用:在 Zustand 中使用 Immer 中间件获得可变语法
技术局限与边界
1. Proxy 浏览器兼容性
Valtio 依赖 JavaScript Proxy API,需要 ES2015+ 环境。不支持 IE 11 及更老的浏览器。这在 2026 年已不是问题,但在需要兼容旧浏览器的场景中需注意。
2. 根变量重新赋值陷阱
Proxy 无法拦截变量赋值(state = newValue),只能拦截属性修改。新手常犯的错误是重新赋值根变量,导致追踪链断裂:
let state = proxy({ count: 0 })
state = proxy({ count: 1 }) // ❌ 新 proxy 与旧追踪断开3. 不可序列化对象的限制
Proxy 不应包裹 DOM 节点、Map、Set 等不可序列化的对象。这些类型应使用 ref() 包裹以排除追踪。
4. 调试难度
可变更新语法虽然简洁,但"修改分散在各处"使得调试不如 Redux 的 dispatch(action) 集中式日志直观。虽然 Valtio 提供了 Chrome Extension,但调试体验不如 Redux DevTools 成熟。
5. 社区生态较小
与 Zustand(58.4k stars)相比,Valtio(10.2k stars)的社区规模较小,第三方中间件、教程和 Stack Overflow 问答较少。
6. 无内置时间旅行
Valtio 的 Chrome Extension 提供基本的状态查看和修改历史,但不像 Redux DevTools 那样支持完整的时间旅行调试。
7. 与 Zustand/Jotai 的定位重叠
同属 pmndrs 生态,Valtio 与 Zustand、Jotai 存在一定的功能重叠。团队需要明确在什么场景下使用哪个库,避免混乱。一般建议:
- 默认用 Zustand
- 需要原子化组合用 Jotai
- 明确偏好 Proxy 可变模式时用 Valtio
8. 深层 Proxy 的性能边界
Valtio 的递归 Proxy 对极深层嵌套的对象结构有轻微的性能开销。在绝大多数业务场景中这不是问题,但在需要频繁创建/销毁大量深层状态的场景中需要留意。
学习资源
官方资源
- Valtio 官方文档 — API 文档和指南
- Announcing Valtio v2 — v2 发布公告
- Valtio GitHub — 源码、Issues、Discussions
- Valtio API: proxy — proxy API 详解
教程与文章
- Valtio: The Proxy-Based State That Makes React State Management Feel Like Magic — 入门教程
- Simplifying State Management in React with Valtio — 实战指南
- Proxy State Management: MobX vs Valtio — MobX 与 Valtio 对比
- A State Management Tour: Proxy State With Valtio — Marmelab 深度解析
对比分析
- Zustand vs Legend-State vs Valtio 2026 — 三库对比指南
- State Management in 2026: Zustand vs Jotai vs Redux Toolkit vs Signals — 2026 全面对比
- React State Management in 2026: A Data-Driven Comparison — 数据驱动分析
- How is Zustand different from Valtio? — pmndrs 社区讨论
集成指南
- Valtio + Lynx.js — 与 Lynx 框架集成
2026 年现状
市场定位
截至 2026 年中,Valtio 以 ~160 万周下载量 和 10.2k GitHub Stars 稳居 React 状态管理生态的第二梯队(仅次于 Zustand、Redux Toolkit、Jotai)。它不是最流行的选择,但在"偏好可变更新语法"的开发者群体中保持着稳定且忠实的用户群。
与 pmndrs 生态的关系
Valtio 与 Zustand、Jotai 同属 pmndrs 组织,由同一作者 Daishi Kato 设计。三者的定位在 2026 年已经非常清晰:
| 库 | 定位 | 核心模型 |
|---|---|---|
| Zustand | 通用状态管理(默认选择) | 单 Store + Hooks |
| Jotai | 原子化状态组合 | 多 Atom + 依赖图 |
| Valtio | Proxy 响应式状态 | 可变 Proxy + Snapshot |
三者可以共存于同一项目,分别处理不同粒度的状态需求。
技术趋势
- React 19 兼容:Valtio v2 完整支持 React 19,包括
use()Hook 集成。 - 稳定迭代中:v2.3.2(2026-05-01)是当前最新版本,处于稳定维护阶段,没有激进的新特性计划。
- Signals 的潜在影响:TC39 Signals Proposal 的推进可能影响 Valtio 的长期定位。Proxy 响应式与 Signals 在理念上有相似之处,但 Signals 更底层且标准化。
- 社区生态扩展:社区贡献了持久化、表单集成等中间件,但规模和成熟度不如 Zustand 生态。
选型结论
Valtio 是 2026 年 React 状态管理中"可变模式"的最佳轻量选择。如果你的团队偏好直接修改对象属性的编码风格(类似 Vue/MobX),且不想承担 MobX 的重量级依赖,Valtio 是最优雅的替代方案。但对于大多数新项目,Zustand 仍然是更安全、社区更大的默认选择。
📅 文档更新时间:2026-07-07
📦 数据来源:GitHub、npm、pmndrs 官方博客、社区对比文章
🔗 基于 Valtio v2.3.2 编写