npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

valtio-observe

v1.4.1

Published

Valtio-observe allows reactive observing expressions/functions using valtio proxies like `const v = useObserve(() => state.x + otherState.y);`

Readme

valtio-observe

CI npm

Valtio-observe allows observing updates of an expression using Valtio proxies and use useObserve in React applications. The expression may be any pure function depending on one or multiple states (valtio proxies).

Install

npm install valtio valtio-observe

Vanilla js/ts usage

observe<T>(func: () => T, consume: (value: T) => void, inSync?: boolean): { sync: () => boolean; stop: () => boolean, restart: () => boolean, isStopped: () => boolean }

The observe excecutes the func and passes its result to the consume function. It subscribes to all proxy properties which getters were accessed while calling the func. Additianally it searches for proxies in the returned value and subscribes to them. The observe returns functions stop, restart, isStopped and sync. The stop and restart should be called to stop and restart observing. The sync can be useful with asynchronous observes and it allows to immediately execute pending updates.

The observe deep-compares the produced value with the presously returned value and omits the consume execution if it is deep-equal. For complex objects the observe reuses the inner objects if they are deep-equal to the ones from the previous result. Note: it calls Object.freeze() for the returned object and all it's inner objects except valtio proxies and valtio refs.

batch(body: () => void): void

The batch is useful with synchronous observes to trigger only one update for multiple changes made in the batch.

Example

import { proxy } from 'valtio/vanilla';
import { observe } from 'valtio-observe/vanilla';

const state1 = proxy({ x: 0 });
const state2 = proxy({ a: { y: 0, ignore: '' } });
const state3 = proxy({ b: { c: { z: 0 } } });

const { stop } = observe(
  () => {
    const x = state1.x;
    const {
      a: { y },
    } = state2; // implicitly calls getters for a and y
    const xy = `${x}:${y}`;
    const p = state3.b.c;
    return { xy, p }; // p is a proxy returned as a whole
  },
  ({ xy, p }) => {
    console.log(`${new Date().toLocaleTimeString()} - ${xy}:${p.z}`);
  },
);

const interval = setInterval(() => {
  state1.x++;

  if (state1.x % 2 == 0) {
    if (state2.a.y % 2 == 0) {
      state2.a.y++;
    } else {
      state2.a = { y: state2.a.y + 1, ignore: '' };
    }
  }

  if (state1.x % 5 == 0) {
    if (state3.b.c.z % 2 == 0) {
      state3.b.c.z++;
    } else {
      state3.b.c = { z: state3.b.c.z + 1 };
    }
  }
}, 1000);

setTimeout(() => {
  clearInterval(interval);
  stop();
}, 30_000);

Usage with React

Signature:

useObserve<T>(func: () => T, inSync?: boolean): T

The useObserve uses the observe and additionally calls snapshot for valtio proxies found in the object. Main differences from useSnapshot:

  1. useSnapshot returns a snapshot of a single proxy while useObserve supports any (pure) expression which can use multiple proxies, function calls and conditional logic; the returned value isn't required to be a proxy.
  2. useSnapshot collects properties/paths accessed during rendering to only trigger re-render when they are modified later (internally it subscribes to the whole proxy and ignores the changes if no property/path values were modified). The useObserve uses property-level subscriptions and only subscribes to the proxy properties accessed during the func calls; additionally it checks if the returned value wasn't changed and omits render if that is deep-equal; if some inner object is deep-equal to the one from the previous result it substitutes that with the instance from the previous result.

Example

import { proxy } from 'valtio';
import { useObserve } from 'valtio-observe';

const state1 = proxy({ x: 0 });
const state2 = proxy({ a: { y: 0 } });
const state3 = proxy({ b: { c: { z: 0 }, ignore: 0 } });

const Test = () => {
  const {
    xy,
    p: { z },
  } = useObserve(() => {
    const x = state1.x;
    const {
      a: { y },
    } = state2;
    const xy = `${x}:${y}`;
    const p = state3.b.c;
    return { xy, p }; // p is a proxy returned as a whole
  });

  console.log('render');

  return (
    <div>
      <button onClick={() => state1.x++}>state1.x++</button>
      <button onClick={() => state2.a.y++}>state2.a.y++</button>
      <button onClick={() => state3.b.c.z++}>state3.b.c.z++</button>
      <button onClick={() => (state2.a = { y: state1.x })}>
        state2.a = {'{'}y: state1.x{'}'}
      </button>
      <button onClick={() => state3.b.ignore++}>state3.b.ignore++</button>
      <div>{`${xy}:${z}`}</div>
    </div>
  );
};

Computed values

As far as the observe identifies all proxy properties directly or inderectly accessed during execution of the result producing function func you can use ordinary functions computing the derived values:

const obj = proxy({x: 42});
const doubled() => 2 * obj.x;
//...
observe(() => doubled(), (value) => {/*...*/}); // vanilla
const value = useObserve(() => doubled()); // with React

You can make the computed value to be a valtio proxy using a computed function:

function computed<T>(func: () => T, inSync?: boolean): { readonly value: T };

The returned object is a valtio proxy with a getter value which returns the (cached) computed value. You can stop, restart and sync the computation using the handle function:

const obj = proxy({ x: 0, y: 0 });
const c = computed(() => `${obj.x}:${obj.y}`, true);
expect(c.value).toEqual('0:0');
obj.x++;
expect(c.value).toEqual('1:0');
obj.y++;
expect(c.value).toEqual('1:1');

handle(c).stop(); // stop processing updates
obj.x++;
expect(c.value).toEqual('1:1');
handle(c).restart(); // start again and process missing updates
expect(c.value).toEqual('2:1');

The computed object is an ordinary valtio proxy which you can use with subscribe or in other computed values.