Introducing valtio-reactive: a Reactive Library Built on Valtio

What Was Missing in Vanilla Valtio

Hi,

Valtio is a proxy-based state management library for React—but it also works in plain JavaScript. Its primary goal is to provide a global-state solution for React, not to solve JavaScript reactivity in general. That said, its vanilla API remains quite useful outside React.

Valtio in Vanilla JavaScript

For example, you can subscribe to changes in a proxy state:

import { proxy, subscribe } from 'valtio/vanilla';

const state = proxy({ count: 0 });
subscribe(state, () => {
  console.log('Count changed:', state.count);
});

state.count++; // → "Count changed: 1"

And you can take snapshots of state over time:

import { proxy, snapshot } from 'valtio/vanilla';

const state = proxy({ count: 0 });
const snap1 = snapshot(state);
state.count++;
const snap2 = snapshot(state);

console.log(snap1, snap2); // → { count: 0 } { count: 1 }

Snapshots are essential for React integration, but there are use cases in vanilla JavaScript, such as keeping a history of changes.

What’s Missing Compared to “Reactive Frameworks”

I’m not very familiar with all the reactive frameworks, so please correct me if I’ve gotten anything wrong. What seems to be missing in Valtio, compared to other reactive frameworks, are two common patterns:

  1. Effects with usage tracking

  2. Computed values with usage tracking

1. Effects with Usage Tracking

Currently, you subscribe by passing the state and a callback:

const state = proxy({ count: 0 });
subscribe(state, () => {
  console.log('Count changed:', state.count);
});

A reactive-style effect would track only the properties you access, without specifying the state object explicitly:

const state = proxy({ count: 0 });
effect(() => {
  console.log('Count changed:', state.count);
});

state.count++; // → "Count changed: 1"

This also supports multiple source states without extra arguments.

2. Computed Values with Usage Tracking

Computed works similarly; while effect doesn’t return anything, computed returns a new proxy state. It looks like this:

const state = proxy({ count: 0 });

const derived = computed({  
  double: () => state.count * 2,
});

console.log(derived.double); // → 0
state.count++;
console.log(derived.double); // → 2

Now, there’s a caveat. Because effects and computed values react immediately to changes, if we want to make multiple updates we need to batch them explicitly. For example:

batch(() => {
  state.count++;
  state.count++;
});

Vanilla Valtio batches by waiting a macrotask, which works for React but not for these reactive primitives.

Introducing valtio-reactive

To fill these gaps, we built valtio-reactive. It implements effect, computed, and batch on top of Valtio:

npm install valtio-reactive

You can import them from the library:

import { effect, computed, batch } from 'valtio-reactive';

“valtio-reactive makes Valtio a reactive library.”

If you’re curious, give it a try and share your feedback. While valtio-reactive isn’t tuned for performance, benchmarking will be interesting too.

Happy coding.

Reply

or to participate.