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

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'))