1. Basic
  2. proxy

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 and batching

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

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 can 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)
})
// will not notify subscribers
state = { user: { name: 'Nina' } }

// instead
let state = proxy({ user: { name: 'Timo' } })

subscribe(state, () => {
  console.log(state.user.name) // logs "Nina"
})
// will notify subscribers
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'))