How to Organize Actions

Valtio is unopinionated about how you structure your state mutation logic. Here are several common patterns for organizing actions.

This pattern keeps state and actions separate, which is excellent for code-splitting and maintainability.

// store.js
import { proxy } from 'valtio';

export const state = proxy({
  count: 0,
  name: 'foo',
});

export const inc = () => {
  ++state.count;
};

export const setName = (name) => {
  state.name = name;
};

2. Actions as a Separate Exported Object

This pattern groups all actions into a single object, which can be convenient for importing.

// store.js
import { proxy } from 'valtio';

export const state = proxy({
  count: 0,
  name: 'foo',
});

export const actions = {
  inc: () => {
    ++state.count;
  },
  setName: (name) => {
    state.name = name;
  },
};

3. Action Methods Defined in State

You can define actions as methods directly on the state object. Arrow functions are recommended to avoid issues with this context.

// store.js
import { proxy } from 'valtio';

export const state = proxy({
  count: 0,
  name: 'foo',
  inc: () => {
    ++state.count; // References the exported `state` directly
  },
  setName: (name) => {
    state.name = name;
  },
});

4. Action Methods Using this (Advanced)

Using this is possible but can be tricky. When calling state.inc(), this correctly refers to the proxy. However, if you call snap.inc() on a snapshot, this will refer to the immutable snapshot, and the mutation will fail.

// store.js
import { proxy } from 'valtio';

export const state = proxy({
  count: 0,
  name: 'foo',
  inc() {
    ++this.count;
  },
  setName(name) {
    this.name = name;
  },
});

5. Using a Class

For those who prefer an object-oriented approach, you can define your state and actions within a class and then wrap an instance of it with proxy.

// store.js
import { proxy } from 'valtio';

class Store {
  count = 0;
  name = 'foo';

  inc() {
    ++this.count;
  }

  setName(name) {
    this.name = name;
  }
}

export const state = proxy(new Store());