proxy
The proxy tracks changes to the original object and all nested objects, notifying listeners when an object is modified.
import { proxy, useSnapshot } from 'valtio'
const state = proxy({ count: 0, text: 'hello' })
Mutate from anywhere
You can make changes to it in the same way you would to a normal js-object.
setInterval(() => {
++state.count
}, 1000)
Optimizations
Noop
Updates that set the value of a property to the same value are ignored. Subscribers will not be informed of a version change.
const state = proxy({ count: 0 })
state.count = 0 // has no effect
Batching
Multiple changes in the same event loop tick to will be batched together. Subscribers will be notified of a single version change.
const state = proxy({ count: 0, text: 'hello' })
// subscribers will be notified once after both mutations
state.count = 1
state.text = 'world'
Nested proxies
Proxies and be nested in other proxy objects and updated as a whole.
import { proxy, useSnapshot } from 'valtio'
const personState = proxy({ name: 'Timo', role: "admin" })
const authState = proxy({ status: "loggedIn", user: personState })
authState.user.name = 'Nina'
Gotchas
If you reassign the proxy to a entirely new object, it will stop working.
let state = proxy({ user: { name: 'Timo' } })
subscribe(state, () => {
console.log(state.user.name) // not called
})
state = {user: {name: 'Nina'}}
// do
let state = proxy({ user: { name: 'Timo' } })
subscribe(state, () => {
console.log(state.user.name) // logs "Nina"
})
state.user.name = "Nina"
Not everything can be proxied. Generally, you are safe if it is serializable. Classes can also be proxied. But avoid special objects.
// these won't work - changes to these objects won't cause updates
// to store state that is unproxied see the docs on ref
const state = proxy({
chart: d3.select('#chart'),
component: React.createElement('div'),
map: new Map(), // see proxyMap
storage: localStorage
})
// this will work
class User {
first = null
last = null
constructor(first, last) {
this.first = first
this.last = last
}
greet() {
return `Hi ${this.first}!`
}
get fullName() {
return `${this.first} ${this.last}`
}
}
const state = proxy(new User('Timo', 'Kivinen'))