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

mobx-bind

v0.6.3

Published

Utility library for binding MobX observables and observable collections to generic entities

Readme

mobx-bind

A small set of utilities for binding MobX observables and observable collections to generic entities. In the same way React maps your models to a DOM representation, this library can map your models to virtually any other representation implemented in other libraries. Read on for examples.

Principles:

A 'model' is your data representation of a object, which typically contains MobX-observable properties.

An 'entity' is something that is derived from your models, or more typically collections of your models.

A 'lifecycle' is a description of how an entity is created, updated by a model, and destroyed.

export interface EntityLifecycle<TModel, TEntity, TContext> {
    /**
     * Creates an entity to represent the model
     */
    create(model: TModel, context?: TContext): TEntity;

    /**
     * Updates the entity based on the observable model data. This function will be wrapped in
     * `autorun` which means changes to your model are mapped to your entity automatically
     */
    update(model: TModel, entity: TEntity, context?: TContext): void;

    /**
     * Destroys the entity
     */
    destroy(model: TModel, entity: TEntity, context?: TContext): void;
}

Example Use Case: Google Maps

The original purpose of this library was to bind models to Google Maps entities. For example, you may have a PointOfInterest model which you want to map to a Google Maps' Marker. The binding between the two can be defined with an EntityLifecycle object:

import { observable } from 'mobx';
import { bindModel, EntityLifecycle } from 'mobx-bind';

class PointOfInterest {
    constructor(name: string, position: [number, number]) {
        this.name = name;
        this.position = position;
    }
    @observable public name: string;
    @observable public position: [number, number];
}

function createPoiMarkerLifecycle(map: google.maps.Map): EntityLifecycle<PointOfInterest, google.maps.Marker, void> {
    return {
        create(model) {
            // `create` is called in order to create a Marker for your model. Note that `update` is always called immediately
            // following `create` so the only code needed here is that specific to the creation of the entity, not necessarily
            // the whole initialization
            return new google.maps.Marker({ map });
        },
        update(model, entity) {
            // The library will wrap `update` in an `autorun`, causing it to rerun every time the applicable parts of
            // your model changes. Google Maps' Marker has a `setOptions` method which allows us to do this conveniently
            entity.setOptions({
                title: model.name,
                position: new google.maps.LatLng(model.position[0], model.position[1])
            });
        },
        destroy(model, entity) {
            // `destroy` is called when you `dispose` your bound model, or it is removed from a bound collection.
            // This lets you clean up your entity.
            entity.setMap(null);
        }
    };
}

const poiMarkerLifecycle = createPoiMarkerLifecycle(new google.maps.Map(...));

const myPoi = new PointOfInterest('Buckingham Palace', [51.501476, -0.140634]);
bindModel(myPoi, poiMarkerLifecycle);

// Changing your model will automatically update your entity
setTimeout(() => myPoi.name = "The Queen's House", 1000);

Perhaps more useful is the ability to bind to a collection of models, which will automatically manage the creation and destruction of entities for those models.

This can be done with either IObservableArrays or ObservableMaps using either

... bindMap

import { observable } from 'mobx';
import { bindMap } from 'mobx-bind';

const myPois = observable.shallowMap([
    ['1', new PointOfInterest('Buckingham Palace', [51.501476, -0.140634])],
    ['2', new PointOfInterest('Big Ben', [51.510357, -0.116773])],
    ['3', new PointOfInterest('Natural History Museum', [51.495915, -0.176366])]
]);
bindMap(myPois, poiMarkerLifecycle);

// Changing your model will automatically update your entity
setTimeout(() => myPois.get('1').name = 'Westminster', 1000);

// Changing your collection will also automatically update your derived entities
setTimeout(() => myPois.delete('1'), 2000);
setTimeout(() => myPois.set('4', new PointOfInterest('10 Downing Street', [51.503186, -0.126416])), 3000);

... or bindArray:

import { observable } from 'mobx';
import { bindArray } from 'mobx-bind';

const myPois = observable.shallowArray([
    new PointOfInterest('Buckingham Palace', [51.501476, -0.140634]),
    new PointOfInterest('Big Ben', [51.510357, -0.116773]),
    new PointOfInterest('Natural History Museum', [51.495915, -0.176366])
]);
bindArray(myPois, poiMarkerLifecycle);

// Changing your model will automatically update your entity
setTimeout(() => myPois[1].name = 'Westminster', 1000);

// Changing your collection will also automatically update your derived entities
setTimeout(() => myPois.splice(1, 1), 2000);
setTimeout(() => myPois.push(new PointOfInterest('10 Downing Street', [51.503186, -0.126416])), 3000);