从 Valtio v1 迁移到 v2 的完整指南
前言:为什么要迁移到 v2?
还在为 React 状态管理而烦恼吗?Valtio v2 带来了革命性的改进!作为轻量级的代理状态管理库,Valtio v2 不仅完全拥抱 React 19 的新特性,还优化了性能表现和开发体验。本文将为你提供从 v1 到 v2 的完整迁移指南,让你在 30 分钟内完成平滑升级。
读完本文你将获得:
- ✅ Valtio v2 的核心变化解析
- ✅ Promise 处理的最佳实践方案
- ✅ 对象复用的安全迁移策略
- ✅ SSR 环境下的兼容性解决方案
- ✅ 完整的代码示例和对比表格
Valtio v2 的核心变化概览
Valtio v2 主要围绕三个关键变化进行了重构:
版本要求升级
- React: ≥ 18.0.0(必需)
- TypeScript: ≥ 4.5.0(必需)
- 构建目标: ES2018
已移除的废弃功能
所有在 v1 中标记为废弃的 API 已被完全移除,确保代码库的整洁性。
核心迁移场景详解
1. Promise 处理的革命性变化
Valtio v2 最大的变化是放弃了内部的 Promise 处理机制,转而完全依赖 React 19 的 use hook。
v1 的 Promise 处理方式
// v1 - 自动处理 Promise
import { proxy, useSnapshot } from 'valtio'
const state = proxy({
data: fetch('/api/data').then(res => res.json())
})
const Component = () => {
const snap = useSnapshot(state)
// v1 内部自动解析 Promise
return <div>{JSON.stringify(snap.data)}</div>
}
v2 的正确迁移方式
// v2 - 显式使用 use hook
import { use } from 'react' // React 19 原生支持
import { proxy, useSnapshot } from 'valtio'
const state = proxy({
data: fetch('/api/data').then(res => res.json())
})
const Component = () => {
const snap = useSnapshot(state)
// v2 需要显式使用 use hook
return <div>{JSON.stringify(use(snap.data))}</div>
}
React 18 用户的兼容方案
// React 18 用户需要使用 shim
import { use } from 'react18-use' // 第三方兼容库
import { proxy, useSnapshot } from 'valtio'
const state = proxy({
data: fetch('/api/data').then(res => res.json())
})
const Component = () => {
const snap = useSnapshot(state)
return <div>{JSON.stringify(use(snap.data))}</div>
}
2. proxy() 函数的行为变化
Valtio v2 中 proxy(obj) 从纯函数变为非纯函数,这会影响到对象复用的场景。
推荐用法(v1 和 v2 都兼容)
import { proxy } from 'valtio'
// ✅ 推荐:不重用传入的对象
const state = proxy({ count: 1, obj: { text: 'hi' } })
// ✅ 安全操作
state.obj = { text: 'hello' }
对象复用场景的迁移方案
// v1 - 对象复用模式
import { proxy } from 'valtio'
const initialObj = { count: 1, obj: { text: 'hi' } }
const state = proxy(initialObj)
// 后续继续使用 initialObj...
const newObj = { text: 'hello' }
state.obj = newObj
// 后续继续使用 newObj...
// v2 - 需要显式深拷贝
import { proxy } from 'valtio'
import { deepClone } from 'valtio/utils'
const initialObj = { count: 1, obj: { text: 'hi' } }
const state = proxy(deepClone(initialObj))
// 安全使用 initialObj...
const newObj = { text: 'hello' }
state.obj = deepClone(newObj)
// 安全使用 newObj...
3. useSnapshot() 的优化调整
v2 中对 useSnapshot() 进行了细微调整以确保与 useMemo 和未来 React 编译器的兼容性。虽然可能在极端情况下导致额外的重渲染,但对大多数应用来说影响微乎其微。
4. SSR 环境下的 useLayoutEffect 警告
在 React 18 SSR 环境中,需要添加条件逻辑来避免过多的警告:
import { snapshot, useSnapshot as useSnapshotOrig } from 'valtio'
// 检测是否为 SSR 环境
const isSSR = typeof window === 'undefined'
// 条件性 useSnapshot
export const useSnapshot = isSSR
? (p) => snapshot(p) // SSR 使用 snapshot
: useSnapshotOrig // 客户端使用原始 useSnapshot
// 在组件中正常使用
const Component = () => {
const snap = useSnapshot(state)
return <div>{snap.count}</div>
}
迁移检查清单
为了确保迁移过程顺利,请按照以下清单逐步检查:
| 检查项 | v1 状态 | v2 迁移方案 | 完成状态 |
|---|---|---|---|
| Promise 使用 | ❌ 内部自动处理 | ✅ 显式使用 use hook | □ |
| 对象复用 | ❌ 可能产生副作用 | ✅ 使用 deepClone | □ |
| React 版本 | ≥ 16.0.0 | ≥ 18.0.0 | □ |
| TypeScript | ≥ 3.0.0 | ≥ 4.5.0 | □ |
| SSR 兼容性 | ❌ 可能有警告 | ✅ 条件性 useSnapshot | □ |
常见问题解答
Q: 迁移到 v2 后性能会下降吗?
A: 不会。虽然 useSnapshot 有细微调整,但整体性能保持优秀,且更好的兼容性为未来优化奠定了基础。
Q: 如果我的项目还在用 React 17 怎么办?
A: 必须升级到 React 18 或更高版本。Valtio v2 强制要求 React ≥ 18.0.0。
Q: deepClone 的使用会影响性能吗?
A: 只在对象复用场景需要,正常使用模式下不会增加任何性能开销。
Q: 迁移过程中遇到问题如何调试?
A: 建议逐步迁移,先处理 Promise 相关代码,再检查对象复用场景,最后处理 SSR 兼容性。
总结
Valtio v2 的迁移虽然涉及一些 breaking changes,但整体迁移路径清晰明确。核心变化围绕:
- Promise 处理现代化 - 拥抱 React 19 use hook
- 对象操作安全化 - 显式深拷贝避免副作用
- 兼容性最优化 - 更好的 React 生态集成
遵循本文的指南,你可以在短时间内完成从 v1 到 v2 的平滑迁移,享受更现代化、更安全的开发体验。
💡 提示:迁移完成后,建议运行完整的测试套件,确保所有功能正常工作。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



