本人主要是在react中用到了valtio,遇到了相关问题,记录一下。
首先,两个API,是最基础的也是最重要的,proxy与useSnapshot。
proxy
代理状态,将要管理的值用proxy代理起来
import { proxy } from 'valtio'
const state = proxy({ count: 0, text: 'hello' })
useSnapshot
得到具有响应式且只读的值
const snap = useSnapshot(state)
在react中,想实时监听值的变化,用useSnapshot搭配useEffect即可
ref
用ref代理某个值后,改变该值,不会触发监听
subscribe/subscribeKey/watch都不会触发
export const store = proxy<{ refTest: number[] }>({
refTest: ref([0])
})
subscribe
不能写在组件内,否则会因组件的重新渲染而重复生成
- 可以监听一个整个proxy
- 也可以值监听里面的某个值,但这个值必须是复杂数据类型
- 返回值可以停止订阅
const unsubscribe = subscribe(store, () =>
console.log('store has changed to', store)
)
snapshot
获取代理并返回一个不可变的对象
proxy发生变化,这个对象也不会更改
import { proxy, snapshot } from 'valtio'
const store = proxy({ name: 'Mika' })
const unwrappedStore = snapshot(store) // unwrapped store is the original object, unproxied
const anotherUnwrappedStore = snapshot(store)
console.log(unwrappedStore === anotherUnwrappedStore) // true
store.name = 'Hanna'
const yetAnotherUpwrappedStore = snapshot(store)
console.log(unwrappedStore === yetAnotherUpwrappedStore) // false
subscribeKey
不能写在组件内,否则会因组件的重新渲染而重复生成
订阅一个值。官网说订阅一个基本数据类型
subscribeKey(store, 'todos', v => {
console.log(v, 'todos')
})
watch
不能写在组件内,否则会因组件的重新渲染而重复生成
- 会立即执行一次
- 参数:一个函数,函数参数是一个方法,传入proxy即可监听
- 可以return一个函数,该函数会在watch之前运行
watch(get => {
console.log(get(store))
return () => {
if (store.boolean === true) {
console.log(123)
}
}
})
setTimeout(() => {
store.boolean = true
}, 1000)
// 先log了123,再log get(store)
devtools
调试工具,将proxy放进去即可,然后就可以在浏览器用redux调试工具查看状态了
devtools(store, { name: 'store', enabled: true })
derive/underive
类似于计算属性
const derived = derive({
doubled: get => get(store).count * 2
})
<div>{derived.doubled}</div>
可以调用underive停止监听
proxyWithHistory
这个API代理会记录历史记录
undo上一个记录
redo下一个记录
export const historyProxy = proxyWithHistory({ num: 0 })
const { value, undo, redo } = useSnapshot(historyProxy)
<button onClick={() => historyProxy.value.num++}>+1</button>
<button onClick={() => undo()}>undo</button>
<button onClick={() => redo()}>redo</button>
proxySet
只能设置number数组
import { proxySet } from 'valtio/utils'
const state = proxySet([1, 2, 3])
state.add(4)
state.delete(1)
state.forEach((v) => console.log(v)) // ---> 2,3,4
亦可把proxySet放到proxy中
import { proxySet } from 'valtio/utils'
const state = proxy({
count: 1,
set: proxySet(),
})
proxyMap
用法和原生Map一样,但若在proxy用new Map(),值发生变化是不会触发监听的,用proxyMap则可以触发监听
亦可把proxyMap放到proxy中
import { proxyMap } from 'valtio/utils'
const state = proxy({
count: 1,
map: proxyMap(),
})
可以用ref作为key
// with ref
const key = ref({})
state.set(key, 'hello')
state.get(key) //hello
// without ref
const key = {}
state.set(key, 'value')
state.get(key) //undefined