扫一扫分享
npm i valtio使代理状态变得简单
使用体验下来,简直就是 react 版本的 Pinia。
Valtio 将您传递给它的对象转变为一个自我感知的代理。
import { proxy, useSnapshot } from 'valtio'
const state = proxy({ count: 0, text: 'hello' })
您可以按照与普通 js 对象相同的方式对其进行更改。
setInterval(() => {
++state.count
}, 1000)
创建捕获更改的本地快照。经验法则:从渲染函数中的快照读取,否则使用源。仅当您访问的状态部分发生更改时,该组件才会重新渲染,它是渲染优化的。
// This will re-render on `state.count` change but not on `state.text` change
function Counter() {
const snap = useSnapshot(state)
return (
<div>
{snap.count}
<button onClick={() => ++state.count}>+1</button>
</div>
)
}
注意:useSnapshot 返回一个新的代理以进行渲染优化。
TypeScript 用户注意:useSnapshot 的返回类型可能过于严格。
如果您对此不熟悉,强烈建议使用 eslint-plugin-valtio。
您可以访问组件外部的状态并订阅更改。
import { subscribe } from 'valtio'
// Subscribe to all state changes
const unsubscribe = subscribe(state, () =>
console.log('state has changed to', state),
)
// Unsubscribe by calling the result
unsubscribe()
您还可以订阅状态的一部分。
const state = proxy({ obj: { foo: 'bar' }, arr: ['hello'] })
subscribe(state.obj, () => console.log('state.obj has changed to', state.obj))
state.obj.foo = 'baz'
subscribe(state.arr, () => console.log('state.arr has changed to', state.arr))
state.arr.push('world')
要订阅状态的原始值,请考虑subscribeKey在 utils 中。
import { subscribeKey } from 'valtio/utils'
const state = proxy({ count: 0, text: 'hello' })
subscribeKey(state, 'count', (v) =>
console.log('state.count has changed to', v),
)
还有另一个实用程序watch在某些情况下可能会很方便。
import { watch } from 'valtio/utils'
const state = proxy({ count: 0 })
const stop = watch((get) => {
console.log('state has changed to', get(state)) // auto-subscribe on use
})
Valtio 支持 React-suspense 并将抛出您在组件渲染函数中访问的承诺。这消除了所有异步来回,您可以直接访问数据,而父级负责回退状态和错误处理。
const state = proxy({ post: fetch(url).then((res) => res.json()) })
function Post() {
const snap = useSnapshot(state)
return <div>{snap.post.title}</div>
}
function App() {
return (
<Suspense fallback={<span>waiting...</span>}>
<Post />
</Suspense>
)
}
如果您有大型嵌套对象以及您不想代理的访问器,这可能很有用。ref允许您将这些对象保留在状态模型中。
有关更多信息,请参阅#61和#178 。
import { proxy, ref } from 'valtio'
const state = proxy({
count: 0,
dom: ref(document.body),
})
您可以读取组件中的状态,而不会导致重新渲染。
function Foo() {
const { count, text } = state
// ...
或者,您可以通过订阅 useEffect 来获得更多控制。
function Foo() {
const total = useRef(0)
useEffect(() => subscribe(state.arr, () => {
total.current = state.arr.reduce((p, c) => p + c)
}), [])
// ...
默认情况下,状态突变在触发重新渲染之前进行批处理。有时,我们想禁用批处理。已知的用例是<input> #270。
function TextBox() {
const snap = useSnapshot(state, { sync: true })
return (
<input value={snap.text} onChange={(e) => (state.text = e.target.value)} />
)
}
您可以将Redux DevTools Extension用于普通对象和数组。
import { devtools } from 'valtio/utils'
const state = proxy({ count: 0, text: 'hello' })
const unsub = devtools(state, { name: 'state name', enabled: true })
使用 Redux DevTools 操作状态
Valtio 不依赖于 React,您可以在 vanilla-js 中使用它。
import { proxy, subscribe, snapshot } from 'valtio/vanilla'
// import { ... } from 'valtio/vanilla/utils'
const state = proxy({ count: 0, text: 'hello' })
subscribe(state, () => {
console.log('state is mutated')
const obj = snapshot(state) // A snapshot is an immutable object
})
虽然代理状态与其快照的分离很重要,但它会让初学者感到困惑。我们有一个方便的实用程序来改善开发人员体验。 useProxy 返回浅代理状态及其快照,这意味着您只能在根级别上进行变异。
import { useProxy } from 'valtio/utils'
const state = proxy({ count: 1 })
const Component = () => {
// useProxy returns a special proxy that can be used both in render and callbacks
// The special proxy has to be used directly in a function scope. You can't destructure it outside the scope.
const $state = useProxy(state)
return (
<div>
{$state.count}
<button onClick={() => ++$state.count}>+1</button>
</div>
)
}
您可以使用对象 getter 定义计算属性。
const state = proxy({
count: 1,
get doubled() {
return this.count * 2
},
})
将其视为高级用法,因为 的行为this有时会令人困惑。
欲了解更多信息,请查看本指南。
这是一个实用函数,用于创建具有快照历史记录的代理。
import { proxyWithHistory } from 'valtio-history'
const state = proxyWithHistory({ count: 0 })
console.log(state.value) // ---> { count: 0 }
state.value.count += 1
console.log(state.value) // ---> { count: 1 }
state.undo()
console.log(state.value) // ---> { count: 0 }
state.redo()
console.log(state.value) // ---> { count: 1 }
这是为了创建一个模仿本机 Set 行为的代理。该API与Set API相同
import { proxySet } from 'valtio/utils'
const state = proxySet([1, 2, 3])
//can be used inside a proxy as well
//const state = proxy({
// count: 1,
// set: proxySet()
//})
state.add(4)
state.delete(1)
state.forEach((v) => console.log(v)) // 2,3,4
这是为了创建一个模拟本机 Map 行为的代理。 API与地图API相同
import { proxyMap } from 'valtio/utils'
const state = proxyMap([
['key', 'value'],
['key2', 'value2'],
])
state.set('key', 'value')
state.delete('key')
state.get('key') // ---> value
state.forEach((value, key) => console.log(key, value)) // ---> "key", "value", "key2", "value2"
Valtio 与 React 一起使用并支持钩子 (>=16.8)。它仅依赖于react任何渲染器并与任何渲染器配合使用,例如react-dom、react-native、react-three-fiber等。
Valtio 适用于 Node.js、Next.js 和其他框架。
Valtio 也可以在没有 React 的情况下工作。
手机预览