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

or to participate.