- Daishi Kato's Read the Code
- Posts
- A Simplified Version of Valtio
A Simplified Version of Valtio
What If the Proxy Only Handled Shallow State?
Hi,
A couple of years ago, I shared a simplified version of Jotai, which helped people understand the basic idea behind its implementation.
🔗 Jotai Core Internals
I think I haven’t done the same for Valtio—until now. Today, I came up with a simplified version of Valtio that only shallowly wraps the object in a proxy.
But Wait—Valtio Is Meant for Deep Proxies
To be clear, the entire purpose of Valtio is to support deep proxies, because that’s what’s needed to comply with React’s immutability contract.
Still, simplifying the core idea can be helpful for learning. So here’s a version that only proxies the top level:
The Simplified Implementation
const SNAPSHOT = Symbol();
const LISTENERS = Symbol();
export const proxy = (baseObj) => {
let snap = { ...baseObj };
const listeners = new Set();
return new Proxy(baseObj, {
set(target, prop, value, receiver) {
const result = Reflect.set(target, prop, value, receiver);
snap = { ...target };
listeners.forEach((fn) => fn());
return result;
},
get(target, prop, receiver) {
if (prop === SNAPSHOT) {
return snap;
}
if (prop === LISTENERS) {
return listeners;
}
return Reflect.get(target, prop, receiver);
},
});
};
export const snapshot = (p) => p[SNAPSHOT];
export const subscribe = (p, fn) => {
const listeners = p[LISTENERS];
listeners.add(fn);
return () => listeners.delete(fn);
};
import { useCallback, useSyncExternalStore } from 'react';
export const useSnapshot = (p) =>
useSyncExternalStore(
useCallback((fn) => subscribe(p, fn), [p]),
() => snapshot(p),
);
A Quick Note
I haven’t tested this code, so don’t be surprised if it has bugs. Feel free to try it out and fix whatever doesn’t work.
Happy coding.
Reply