- Daishi Kato's Read the Code
- Posts
- Introducing valtio-reactive: a Reactive Library Built on Valtio
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:
Effects with usage tracking
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