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 🙏

© 2025 – Pkg Stats / Ryan Hefner

use-observable-mobx

v0.1.3

Published

A deeply reactive hook for MobX that efficiently tracks property access in React components as an alternative to the [`observer` HOC](https://mobx.js.org/react-integration.html).

Readme

use-observable-mobx

A deeply reactive hook for MobX that efficiently tracks property access in React components as an alternative to the observer HOC.

Installation

npm install use-observable-mobx
# or
yarn add use-observable-mobx
# or
pnpm add use-observable-mobx

Features

  • Deeply Reactive: Automatically tracks and reacts to all accessed properties, including nested objects and arrays
  • Efficient Rendering: Components rerender only when accessed properties change

Usage

import { makeAutoObservable } from "mobx";
import { useState } from "react";
import { useObservable } from "use-observable-mobx";

interface Item {
  id: number;
  text: string;
}

class Store {
  counter = 0;
  items: Item[] = [{ id: 1, text: "Item 1" }];

  constructor() {
    makeAutoObservable(this);
  }

  increment() {
    this.counter++;
  }

  addItem(text: string) {
    this.items.push({
      id: this.items.length + 1,
      text,
    });
  }
}

const store = new Store();

const Counter = () => {
  const { counter, increment } = useObservable(store);

  return (
    <div>
      <p>Count: {counter}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

// Or compose hooks without needing to import the store again
const useStore = () => useObservable(store);

const ItemList = () => {
  const { items, addItem } = useStore();
  const [text, setText] = useState("");

  return (
    <div>
      <ul>
        {items.map((item) => (
          <li key={item.id}>{item.text}</li>
        ))}
      </ul>

      <input value={text} onChange={(e) => setText(e.target.value)} />
      <button
        onClick={() => {
          addItem(text);
          setText("");
        }}
      >
        Add Item
      </button>
    </div>
  );
};

Advanced Usage

Unwrapping Proxies

Sometimes you need to access the original MobX object without the reactive proxy, such as when placing an object in React context or passing it to a function that expects the original object.

import { type PropsWithChildren, createContext } from "react";
import { useObservable } from "use-observable-mobx";

const ItemContext = createContext<Item | null>(null);

const useItemContext = () => {
  const item = useContext(ItemContext);

  if (!item) {
    throw new Error("useItemContext must be used within an ItemProvider");
  }

  return useObservable(item);
};

const ItemProvider = ({
  children,
  item,
}: PropsWithChildren<{ item: Item }>) => (
  // Unwrap when passing to context to keep the mobx object reference the same
  <StoreContext.Provider value={useObservable.unwrap(item)}>
    {children}
  </StoreContext.Provider>
);

const Item = () => {
  const item = useItemContext();

  return <li>{item.text}</li>;
};

const ItemList = () => {
  const { items, addItem } = useCounter();
  const [text, setText] = useState("");

  return (
    <div>
      <ul>
        {items.map((item) => (
          <ItemProvider key={item.id} item={item} />
        ))}
      </ul>

      <input value={text} onChange={(e) => setText(e.target.value)} />
      <button
        onClick={() => {
          addItem(text);
          setText("");
        }}
      >
        Add Item
      </button>
    </div>
  );
};

Checking for Reactive Proxies

import { isReactiveProxy } from "use-observable-mobx";

const MyComponent = () => {
  const store = useObservable(myStore);

  console.log(isReactiveProxy(store)); // true
  console.log(isReactiveProxy({})); // false
};

How It Works

The useObservable hook creates a deeply reactive proxy that:

  1. Tracks all property access during render
  2. Subscribes to MobX observables for those properties
  3. Triggers re-renders when any accessed property changes

Unlike traditional MobX integration approaches, this hook doesn't require wrapping components in observers or using special syntax. It simply works by tracking what you actually use in your component.

Inspiration

This library was inspired by:

Acknowledgments

  • Valtio: Thanks to Valtio for laying the groundwork for a deeply reactive approach that tracks property access in React components which this library borrows from.
  • MobX: Thanks to the MobX team for their useObserver implementation, which this hook borrows from extensively.

Sponsor

Thanks to Gavel for sponsoring the initial development.

Gavel

License

MIT